Search code examples
c++constructorstlcontainers

Is there still a need to provide default constructors to use STL containers?


I remember that back in C++98, if you wanted to make an STL container of MyClass, you needed to provide default constructor to MyClass.

Was this specific to some implementations of STL? or was it mandated by the standard?

  • Q: Is this not necessary anymore?

Because it is not a good practice to provide default constructors when it makes no sense to have one...

Of course, I am not talking about the calls like

vector<MyClass> v(6);  

where you explicitly request that 6 default-initialized objects are to be created...


Solution

  • This quote is from the C++ Programming Language, Special edition , 2005 by Bjarne Stroustrup in section 16.3.4:

    If a type does not have a default constructor, it is not possible to create a vector with elements of that type, without explicitly providing the value of each element.

    So it was indeed a standard requirement. It was also required that (section 17.1.4) :

    To be an element of a container, an object must be of a type that allows the container implementation to copy it. The container may copy it using a copy constructor or an assignment; in either case the result of the copy must be an equivalent object.

    So yes, there were "official" constructor requirementsand the library implementation were supposed to be interchangeable and not add other requirements. (Already in the very first proposal for STL in 1995, the authors tried as much as possible to clearly indicate specifications and narrow down the implementation dependent flexibility.)

    You therefore had to provide a default constructor in the case where you declared other constructors:

    If a user has declared a default constructor, that one will be used; otherwise, the compiler will try to generate one if needed and if the user hasn't declared other constructors.

    Nowadays, this requirement is relaxed. Since C++11:

    The requirements that are imposed on the elements depend on the actual operations performed on the container.

    So you can define a vector for a class without default constructor, if it doesn't make sense. This for example perfectly works (online demo):

    class MyClass {
    public: 
        MyClass(int x) {}
    };
    int main() {
        vector<MyClass> v; 
        MyClass test{1}; 
        v.push_back(test);
    }
    

    But it works only as long as you don't use any operation that would need the default constructor. For instance v.resize(6); would fail to compile.