Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can std::vector move its data to another address at emplace_back() even though there is still unused space according to capacity()?

Is it guaranteed that std::vector only moves its data when size()==capacity() and calling push_back() or emplace_back() or can it do it otherwise also?

like image 935
kynnysmatto Avatar asked Jun 01 '16 14:06

kynnysmatto


People also ask

What does vector Emplace_back do?

The C++ function std::vector::emplace_back() inserts new element at the end of vector. Reallocation happens if there is need of more space. This method increases container size by one.

Does Emplace_back use move constructor?

Calling emplace_back will call the move constructor of std::string when std::move is used, which could save on a copy (so long as that string isn't stored in a SSO buffer). Note that this is essentially the same as push_back in this case.

Which is faster push back or Emplace_back?

With the simple benchmark here, we notice that emplace_back is 7.62% faster than push_back when we insert 1,000,000 object (MyClass) into an vector. Insert 1,000,000 objects.


2 Answers

The specification is a bit indirect. capacity is specified as:

size_type capacity() const noexcept; 

Returns: The total number of elements that the vector can hold without requiring reallocation.

The second part comes from reserve:

reserve(size_type n); 

Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. No reallocation shall take 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 of capacity().

From that you can conclude that if the size is less than the capacity, then insertion does not cause reallocation.

There is no single, direct statement that the vector will not reallocate if there is spare capacity and you haven't explicitly called reserve. However, there is a general container requirement in [container.requirements.general]:

Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

Finally, we have description of the effects of insertion:

[insert/emplace_back/push_back:] 

Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

Putting it all together: Unless otherwise specified, calling a member function does not invalidate iterators. Reallocation invalidates iterators (as described as part of reserve above), so unless otherwise specified, calling a member function, and in particular an insertion, does not reallocate, One such an overriding specification is given for the case where the new size exceeds the current capacity.

like image 133
Kerrek SB Avatar answered Sep 26 '22 02:09

Kerrek SB


The description of standard is not clear enough.

$23.3.6.5 vector modifiers [vector.modifiers]:

Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

So when add elements to std::vector reallocation will certainly happen when the new size is greater than current capacity, but it doesn't says reallocation won't happen even if the new size is less than or equal to current capacity. Anyway if reallocation doesn't happen then all the iterators and references to the elements before the insertion point must remain valid, implies data won't be moved.

It's the same for insert(), emplace_back(), emplace() and push_back().

Quote from cppreference.com just as reference:

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

like image 35
songyuanyao Avatar answered Sep 24 '22 02:09

songyuanyao