问题
In generic code I was trying to tell an output iterator (in practice a std::back_inserter_iterator
to move a range of elements. To my surprise it looked as if elements were moved in a move-to-back_inserter operation.
#include<algorithm> // move
#include<iterator> // back_inserter
#include<vector>
int main(){
std::vector<std::vector<double> > v(10, std::vector<double>(100));
std::vector<std::vector<double> > w;
assert( not v[0].empty() and w.size() == 0 );
std::copy(v.begin(), v.end(), std::back_inserter(w));
assert( not v[0].empty() and w.size() == 10 );
std::move(v.begin(), v.end(), std::back_inserter(w));
assert( v[0].empty() and w.size() == 20 ); // were v elements moved to w?
}
However I don't think it is possible that elements of v
were really moved to w
, because after all back_inserter
will do a push_back
which implies a copy to w
.
It seems more likely that in the std::move
case, v
elements were moved to a temporary and only then copied into w
.
Is that correct? Is there a std::back_inserter
really moving somehow?
Is there already a variant of std::back_inserter
that takes advantage of move/emplace? Something like an std::back_emplacer
?
回答1:
std::back_inserter() is a convenience function template for creating an std::back_insert_iterator object.
The class std::back_insert_iterator
has already operator=
overloaded for taking rvalue reference types, i.e.:
back_insert_iterator<Container>& operator=(typename Container::value_type&& value);
Therefore, std::back_insert_iterator
is already prepared to take advantage of move semantics.
回答2:
If std::back_insert_iterator
does nothing but calling push_back
on the container it's being constructed with, the question can be answered looking at the std::vector::push_back overload set:
void push_back(const T& value);
void push_back(T&& value);
So, here we obviously have an overload for rvalue references. Wouldn't it be weird, if the corresponding std::back_insert_iterator
copies its argument when invoked with an rvalue reference? And indeed, we again have a very similar overload set:
back_insert_iterator<Container>&
operator=(typename Container::const_reference value);
back_insert_iterator<Container>&
operator=(const typename Container::value_type& value);
with the additional comment that
1) Results in container->push_back(value)
2) Results in container->push_back(std::move(value))
Coming back to your original question
Is there a std::back_inserter really moving somehow?
Yes, the iterator this function creates does take advantage of rvalue reference arguments.
Is there already a variant of std::back_inserter that takes advantage of move/emplace?
No, but it can be implemented. See this answer.
来源:https://stackoverflow.com/questions/54303852/is-there-a-back-inserter-variant-that-takes-advantage-of-move