问题
I tried to do something like:
std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()),
std::make_move_iterator(s2.begin()));
And got this error:
error: using xvalue (rvalue reference) as lvalue
*__result = std::move(*__first);
Which seemed confusing to me. The same thing happens if you use std::move
. It appears that GCC internally uses a function called std::__copy_move_a
which moves rather than copies. Does it matter whether you use std::copy
or std::move
?
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstring>
struct Test
{
typedef std::string::value_type value_type;
std::string data;
Test()
{
}
Test(const char* data)
: data(data)
{
}
~Test()
{
}
Test(const Test& other)
: data(other.data)
{
std::cout << "Copy constructor.\n";
}
Test& operator=(const Test& other)
{
data = other.data;
std::cout << "Copy assignment operator.\n";
return *this;
}
Test(Test&& other)
: data(std::move(other.data))
{
std::cout << "Move constructor.\n";
}
decltype(data.begin()) begin()
{
return data.begin();
}
decltype(data.end()) end()
{
return data.end();
}
void push_back( std::string::value_type ch )
{
data.push_back(ch);
}
};
int main()
{
Test s1("test");
Test s2("four");
std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()),
std::make_move_iterator(s2.begin()));
std::cout << s2.data;
}
回答1:
std::move(a, b, c);
is semantically identical to
std::copy(std::make_move_iterator(a),
std::make_move_iterator(b),
c);
Your efforts to use them both failed because the third argument - the output iterator - should not be a move iterator. You are storing into the third iterator, not moving from it. Both
std::copy(std::make_move_iterator(s1.begin()),
std::make_move_iterator(s1.end()),
s2.begin());
and
std::move(s1.begin(), s1.end(), s2.begin());
should do what you want.
回答2:
std::move
moves the elements if possible, and copies otherwise. std::copy
will always copy.
libstdc++'s copy_move_a
also takes a template parameter _IsMove
. That, and the iterator types, it delegates to a __copy_move
class template that is partially specialized for different iterator categories, etc. but most importantly: Whether to move
or not.
One of the specializations is
#if __cplusplus >= 201103L
template<typename _Category>
struct __copy_move<true, false, _Category>
// first specialized template argument is whether to move
{
template<typename _II, typename _OI>
static _OI
__copy_m(_II __first, _II __last, _OI __result)
{
for (; __first != __last; ++__result, ++__first)
*__result = std::move(*__first); // That may be your line
return __result;
}
};
#endif
Your code fails to compile for a completely different reason: The second range is given through move_iterator
s. If you dereference them, they return an rvalue reference to the object - and you can't assign something to an xvalue of scalar type.
int i;
std::move(i) = 7; // "expression not assignable" -- basically what your code does
The std::move
is implicitly included in *__result
and is of the same value category, that is, an xvalue.
For your example,
std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()),
s2.begin());
should work fine.
来源:https://stackoverflow.com/questions/26432990/are-stdmove-and-stdcopy-identical