[PATCH] Optimize inserting value_type into std::vector

Yubin Ruan ablacktshirt@gmail.com
Sat Jun 18 02:42:00 GMT 2016


Hi, I find the libc++'s `insert(const_iterator, const value_type&)` that 
you mentioned really interesting(and really clever). Just need some help 
to understand some libstdc++ specified code:

 >On 15/06/16 11:34 +0100, Jonathan Wakely wrote:
 >> On 15/06/16 11:15 +0100, Jonathan Wakely wrote:
 >>>     * include/bits/stl_vector.h (vector::_S_insert_aux_assign): Define
 >>>     new overloaded functions.
 >>>     * include/bits/vector.tcc (vector::_M_insert_aux): Use new 
functions
 >>>     to avoid creating a redundant temporary.
 >>>     * 
testsuite/23_containers/vector/modifiers/insert_vs_emplace.cc: New
 >>>     test.
 >>>
 >>> Tested x86_64-linux.
 >>>
 >>> This improves our performance on Howard Hinnant's "insert vs emplace"
 >>> experiment at
 >>> 
http://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html
 >>>
 >>> With this small change there is no difference between emplacing or
 >>> using the relevant insert / push_back function. That also means we
 >>> beat libc++ in some cases, making us the bestest, whoo!
 >>
 >> We still lose to libc++ in one case. For the "lvalue no reallocation"
 >> test our insert and emplace are equal to libc++'s emplace, but
 >> libc++'s insert is even better.
 >
 >Libc++'s insert(const_iterator, const value_type&) is *really* clever.
 >It notices when the object to insert is an element of the vector, and
 >then works out where its updated position would be after shifting the
 >existing elements along, and then copies from the new position. That
 >avoids the copy we make upfront to handle that case safely. Our
 >approach is inefficient for the common case where the object *isn't*
 >in the vector.
 >
 >I guess it's something like:
 >
 > void
 > insert(const_iterator pos, const value_type& x)
 > {
 >   if (cpacity() == size())
 >     {
 >       // reallocate and insert ...
 >       return;
 >     }
 >   auto it = end() - 1;

my question is in regard to the two lines below

 >   *end() = std::move(*it);
 >   ++this->_M_impl._M_finish;

Isn't it illegal to dereference `end()` ?
what does `++this->_M_impl._M_finish` do here ?
Any libstdc++ specified stuff here ?
I haven't read through all of the libstdc++ source, hope that anyone can 
help me understand it or give me some hints.

 >   const value_type* from = std::addressof(x);
 >   for (; it != pos; --it)
 >   {
 >     auto prev = it - 1;
 >     *it = std::move(*prev);

 >     if (std::addressof(*prev) == from)
 >       ++from;

really clever.

 >   }
 >   *pos = *from;
 > }
 >
 >Clever.


Thanks,
Ruan



More information about the Libstdc++ mailing list