Suppose I write
std::vector littleVector(1);
std::vector bigVector;
bigVector.reserve(100);
bigVector = littleVector;
Does t
This depends on the allocator traits.
Here's an excerpt from http://en.cppreference.com/w/cpp/container/vector/operator%3D:
If std::allocator_traits::propagate_on_container_copy_assignment() is true, the target allocator is replaced by a copy of the source allocator. If the target and the source allocators do not compare equal, the target (*this) allocator is used to deallocate the memory, then other's allocator is used to allocate it before copying the elements.(since C++11)
Basically, the memory is reallocated with the new allocator, if the allocators are incompatible (if they cannot deallocate each-other's memory.
It shouldn't matter between vector implementations, but between allocator implementations (which makes sense).
The only requirement on operator=
for standard containers is that afterwards, src == dst
, as specified in Table 96 (in 23.2, General Container Requirements). Furthermore, the same table specifies the meaning of operator ==
:
distance(lhs.begin(), lhs.end()) == distance(rhs.begin(), rhs.end()) // same size
&& equal(lhs.begin(), lhs.end(), rhs.begin()) // element-wise equivalent
Note that this doesn't include capacity in any way. Nor does any other part of the standard mention capacity beyond the general invariant that capacity() >= size()
. The value of capacity after assignment is therefore unspecified, and the container is free to implement assignment whichever way it wants, as long as allocator requirements are kept.
In general, you will find that implementations behave such that
Of course, move assignment is a different story. Since it is generally implemented by stealing the source storage, the capacity will be taken as well.
Unfortunately, the standard underspecifies behavior on allocator-aware sequence container assignment, and indeed is strictly speaking inconsistent.
We know (from Table 28 and from 23.2.1p7) that if allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value
is true
then the allocator is replaced on copy assignment. Further, from Tables 96 and 99 we find that the complexity of copy assignment is linear, and the post-condition on operation a = t
is that a == t
, i.e. (Table 96) that distance(a.begin(), a.end()) == distance(t.begin(), t.end()) && equal(a.begin(), a.end(), t.begin())
. From 23.2.1p7, after copy assignment, if the allocator propagates, then a.get_allocator() == t.get_allocator()
.
With regard to vector capacity, 23.3.6.3 [vector.capacity] has:
5 - Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. It is guaranteed that no reallocation takes place during insertions that happen after a call to
reserve()
until the time when an insertion would make the size of the vector greater than the value ofcapacity()
.
If we take library DR341 as a guide to reading the Standard:
However, the wording of 23.3.6.3 [vector.capacity]paragraph 5 prevents the capacity of a vector being reduced, following a call to reserve(). This invalidates the idiom, as swap() is thus prevented from reducing the capacity. [...]
DR341 was resolved by adding paragraphs into 23.3.6.3:
void swap(vector<T,Allocator>& x);
7 - Effects: Exchanges the contents andcapacity()
of*this
with that ofx
.
8 - Complexity: Constant time.
The conclusion is that from the point of view of the Library committee, operations only modify capacity()
if mentioned under 23.3.6.3. Copy assignment is not mentioned under 23.3.6.3, and thus does not modify capacity()
. (Move assignment has the same issue, especially considering the proposed resolution to Library DR2321.)
Clearly, this is a defect in the Standard, as copy assignment propagating unequal allocators must result in reallocation, contradicting 23.3.6.3p5.
We can expect and hope this defect to be resolved in favour of:
capacity()
on non-allocator-modifying copy assignment;capacity()
on allocator-modifying copy assignment;capacity()
on non-allocator-propagating move assignment;capacity()
on allocator-propagating move assignment.However, in the current situation and until this is clarified you would do well not to depend on any particular behavior. Fortunately, there is a simple workaround that is guaranteed not to reduce capacity()
:
bigVector.assign(littleVector.begin(), littleVector.end());