0

Which constructor does std::vector call when it is making a new instance of the object it's containing? I am under the impression it calls a default constructor but what if one is not defined or is the compiler doing that for me?

Particularly in a case as such:

class Foo
{
    public:
        Foo(int size)
        {
            data = new double[size];
        }


        ~Foo()
        {
            delete[] data;
        }

    private:
        double* data;
};

std::vector<Foo> myVector;
Foo bar(5);
myVector.push_back(bar);
//stuff

How does it know how much memory to allocate when the object has an unknown size until after construction?

Rarge
  • 221
  • 1
  • 4
  • 13
  • 1
    See also http://stackoverflow.com/questions/6142830/how-do-i-initialize-a-stl-vector-of-objects-who-themselves-have-non-trivial-const – Nemo Jun 02 '11 at 23:54

2 Answers2

7

At a minimum, for std::vector<T> to compile, T must be copy-constructible, and copy-assignable. If you want to use std::vector<T>::vector(int) (or std::vector<T>::resize()), then T must have be default-constructible. If any of these requirements are not fulfilled, the code will not compile.

...

C++03 standard, section 23.1 (discussing containers in general):

The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignable types.

Section 20.1.4:

20.1.4 Default construction

The default constructor is not required. Certain container class member function signatures specify the default constructor as a default argument. T() shall be a well-defined expression (8.5) if one of those signatures is called using the default argument (8.3.6).

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 4
    Not entirely true... They do not need to be default-constructible as long as you do not attempt to resize the container without a default initializer. – Nemo Jun 02 '11 at 23:51
  • @Nemo: Sure, you can probably circumvent many "requirements" simply by avoiding the particular container functionality that relies on them! – Oliver Charlesworth Jun 02 '11 at 23:53
  • @Oli: I believe the standard requires them to work that way. Do I need to track down a reference? :-) – Nemo Jun 02 '11 at 23:55
  • @Nemo: A reference would be nice! The more I think about it, the less I like the way that I've phrased my answer, so I'd like to get it correct. – Oliver Charlesworth Jun 02 '11 at 23:56
  • @Oli: Re "A reference would be nice!" Section 23.1.3 of the 2003 standard says you are wrong, CopyConstructible and Assignable. Later on the standard implicitly contradicts itself and says you are right after all. (e.g., resize() uses the default constructor to supply a default value for one of the arguments.) – David Hammen Jun 03 '11 at 00:15
  • @David: Indeed, I've been browsing the standard myself, and I saw such things. I'm hoping my answer is now in a form which is more-or-less correct! – Oliver Charlesworth Jun 03 '11 at 00:20
  • @Oli: I have added the relevant text from the C++98 standard. Please feel free to clean it up, rephrase in your own words, delete with extreme prejudice, or whatever. :-) – Nemo Jun 03 '11 at 00:21
  • @Nemo: No, that's great! After reading the standard myself, I'm in agreement with your original statement. – Oliver Charlesworth Jun 03 '11 at 00:22
1

What happens, after you fix the error:

std::vector<Foo> myVector;
myVector.reserve(10);
myVector.push_back(bar);

is that you have two Foo instances pointing to the same data buffer. It will probably appear to work for a while, but eventually both objects get destroyed, the destructor is called twice (or more, depending on whether the vector needs to move its content around) and the buffer is double-freed, resulting in undefined behavior (which usually means crash).


To address the initial content of the vector, it copy-constructs the pattern you pass in as a parameter (this parameter defaults to a default-constructed object, but doesn't have to be):

std::vector<Foo> myVector(10, bar); // 10 copies of bar
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @Oli: I was addressing the "how does it know how much space to allocate?" by pointing out that `vector` doesn't allocate space for the `data` buffer, just enough for the pointer (which is the actual member of `Foo`). But now I see what you meant. – Ben Voigt Jun 03 '11 at 00:03
  • Ah! Yes, I read the question body before the OP added that second question. – Oliver Charlesworth Jun 03 '11 at 00:08