Consider the following code:
std::vector vec;
vec.reserve(500);
size_t cap = vec.capacity();
std::vector newVec = std::move(vec);
assert(cap == newVec.capacity());
In pretty much any implementation you run across, this will work. I don't care about what implementations do. I want to know what the standard requires. Will the moved-to vector
have the same capacity as the original? Or will the assert trigger?
std::move. std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
The standard mandates that the capacity does not change with a clear as reserve guarantees that further adding of elements do not relocate until the requested capacity is reached. This directly enforces clear to not reduce the capacity.
std::vector typically stores some pointers plus the allocator. When move-constructing a std::vector , only pointers and the allocator have to be moved. The elements don't need to be touched.
C++ Vector Library - reserve() FunctionThe C++ function std::vector::reserve() requests to reserve vector capacity be at least enough to contain n elements. Reallocation happens if there is need of more space.
Looking at the standard, it appears that nothing is required from the move constructor, however as @amaurea says, it would completely defeat the purpose of move semantics if the move constructor were to try and allocate or deallocate memory, so I would expect the capacity to remain the same in all implementations.
23.2.1 General container requirements
Expression
X u(a);
X u = a;
Assertion/note pre-/post-condition
Requires: T
is CopyInsertable into X (see below).
post: u == a
The standard only requires that newVec == vec
. As capacity is not taken into consideration for std::vector::operator==
, newVec
need not necessarily have the same capacity as vec
.
C++11 standard requirements on move constructor for std::vector
are (Table 99 — Allocator-aware container requirements):
X(rv)
X u(rv)
rv
had before this construction; the value of get_allocator()
shall be the same as the value of rv.get_allocator()
before this construction.Here is no requirements/guarantee on capacity. But we can make conclusion that constant complexity implicitly denies any reallocations. And I cannot see any other logical reason to change capacity except reallocation. So it shall be the same.
From the other point of view if the moved-from vector is empty, it is perfectly legal to just ignore it and default-construct itself. This would still be O(1), as it doesn't require any per-element constructs. (Thanks to Nicol Bolas for this issue).
Also implemenation possibly could shrink capacity to the size using hint
parameter of std::allocator::allocate
function:
pointer allocate(size_type, allocator<void>::const_pointer hint = 0);
The use of hint
is unspecified, but intended as an aid to locality if an implementation so desires. So some sofisticated solution possibly could pass vector storage pointer as hint
and use realloc
on it to shrink capacity.
Conclusion: looks like standard doesn't guarantee capacity preserving on moving std::vector
, storage potentially could be shrinked.
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