I ran today against a quite subtle issue I'd like to have your opinion on.
Consider the following garden-variety shared-body-idiom class:
struct S { S() : p_impl(new impl) {} private: struct impl; boost::shared_ptr<impl> p_impl; };
The fun appears when you try to put those into vectors in the following way:
std::vector<S> v(42);
Now, with MSVC 8 at least, all the elements in v
share the same impl
member. Actually, what causes this is the vector
constructor:
template <typename T, typename A = ...> class vector { vector(size_t n, const T& x = T(), const A& a = A()); ... };
Under the scenes, only one S
object gets default constructed, the n
elements of the vector
are copied from it.
Now, with C++11, there are rvalue references. So it cannot work like this. If a vector
is constructed as
std::vector<S> v(42);
then most likely, implementations will chose to default construct the n
objects inside the vector, since copy construction may not be available. This would be a breaking change in this case.
My question is:
std::vector
must have a constructor defined as above, ie. with a default argument ? In particular is there a guarantee that the entries of the vector object get copied instead of default constructed ?PS: Please no comments about the default constructor of the class S
above. It was this or implementing some form of lazy construction.
The default copy constructor will copy all members – i.e. call their respective copy constructors. So yes, a std::vector (being nothing special as far as C++ is concerned) will be duly copied.
Default Constructors in C++ Constructors are functions of a class that are executed when new objects of the class are created. The constructors have the same name as the class and no return type, not even void. They are primarily useful for providing initial values for variables of the class.
The compiler-defined default constructor is required to do certain initialization of class internals. It will not touch the data members or plain old data types (aggregates like an array, structures, etc…). However, the compiler generates code for the default constructor based on the situation.
Does the C++03 standard mandate that
std::vector
must have a constructor defined as above, i.e. with a default argument? In particular is there a guarantee that the entries of the vector object get copied instead of default constructed?
Yes, the specified behavior is that x
is copied n
times so that the container is initialized to contain with n
elements that are all copies of x
.
What does the C++11 Standard say about this same point?
In C++11 this constructor has been turned into two constructors.
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1) explicit vector(size_type n); // (2)
Except for the fact that it no longer has a default argument for the second parameter, (1) works the same way as it does in C++03: x
is copied n
times.
In lieu of the default argument for x
, (2) has been added. This constructor value-initializes n
elements in the container. No copies are made.
If you require the old behavior, you can ensure that (1) is called by providing a second argument to the constructor invocation:
std::vector<S> v(42, S());
I see this as a possibility for a breaking change between C++03 and C++11. I see this as a possibility for a breaking change between C++03 and C++11. Has this issue been investigated? Solved?
Yes, as your example demonstrates, this is indeed a breaking change.
As I am not a member of the C++ standardization committee (and I haven't paid particularly close attention to library-related papers in the mailings), I don't know to what degree this breaking change was discussed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With