Why does an empty vector call the value type's

2019-02-16 06:26发布

问题:

Using g++, I observe that creating a vector of size zero calls the vector's parameterized object type's constructor once. It then is deleted. Why does this happen?

#include <iostream>
#include <vector>
using namespace std;

class s
{
    public:
    s() { cout << endl << "default s constructor" << endl; }
    ~s() { cout << endl << "default s destructor" << endl; }

};

int main()
{
    vector<s> v(0);
}

Output:

default s constructor

default s destructor

回答1:

Because you're explicitly passing an initial size, which calls a constructor that has another parameter whose default value is s(). Just leave out the (0) (i.e. std::vector<s> v;) and it won't happen.

For completeness, the Standard 23.2.4-2 defines the constructor you're calling as:

    explicit vector(size_type n, const T& value =T(),
                                    const Allocator& = Allocator());

Aside (relevant to C++03 but not C++11)

Another interesting behavioural aspect of this constructor also raises its head on S.O. periodically: when the initial number of elements requested is > 0, it copy-constructs those elements from the prototypal parameter to the constructor:

  • people often put a default constructor that leaves member variables uninitialised, hoping to make vector(n) almost as fast as the underlying free store allocation, BUT
  • the copy-constructor is still called n times to copy the "garbage" content of the prototypal object into each of the requested elements

This has an obvious performance cost, but can also crash the application if the garbage content includes e.g. pointers that the copy-constructor can only assume are valid. Similarly, it's extremely dangerous to even push_back such an uninitialised garbage object - it lacks proper value semantic encapsulation and may be copied as the vector resizes, algorithmic operations like std::sort() are performed on the vector etc..



回答2:

The actual constructor you are calling is (from cplusplus.com):

explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );

So even though you only specify the size, a new T object is created for second parameter, and will therefore also be destroyed at the conclusion of the constructor.