c++language-lawyerstdvectorcopy-constructor

Why copying of vector's elements can be done with not-const lvalue argument?


If one copies one std::vector into another, or copies elements of a std::vector in a larger (reserve) or smaller (shrink_to_fit) block of heap memory, what constructor of the element's type is called?

In the example program:

#include <vector>
#include <iostream>

struct A {
    A() {}
    A(A&) { std::cout << "A(A&) "; }
    A(const A&) { std::cout << "A(const A&) "; }
};

int main() {
    std::vector<A> v(1);
    v.reserve(10);
    auto w = v;
    v.shrink_to_fit();
}

I would expect to see A(const A&) A(const A&) A(const A&) output. But in reality the standard library implementations diverge:

Online demo: https://gcc.godbolt.org/z/TTqxv9sd3

Is it right to assume that if the constructor from not-const lvalue is called, then the user code is allowed modifying its argument (at least temporarily)?


Solution

  • I do not see any reason that the library would be required to ensure that the const overload is used.

    The container copy constructor requires per [container.reqmts]/12 that the element type is CopyInsertable from a lvalue v of its type into the container regardless of the const-qualification of v. It also requires the postcondition ([container.alloc.reqmts]/2.4):

    The value of v is unchanged and is equivalent to *p.

    implying that if the non-const copy constructor is used, then it must not result in the value of the original object being different after the call, at least.

    It is a bit less clear to me whether modification of the argument is completely forbidden, because this is stated as postscondition only. I suspect that this is the intent though.