问题
std::move can be used to explicitly allow move semantics when the move wouldn't be already allowed implicitly (such as often when returning a local object from a function).
Now, I was wondering (esp. in the context of local return and implicit move there), if there is such a thing as the inverse of std::move
that will prevent moving the object (but still allow copying).
Does this even make sense?
回答1:
std::move
converts an lvalue into an rvalue, and it does this essentially by static_cast
. The closest to what I can think of as the opposite are these two type casts:
static_cast<T &>(/*rvalue-expression*/)
static_cast<const T&>(/*rvalue-expression*/)
An example of this can be seen below:
#include <iostream>
void f(const int &)
{ std::cout << "const-lval-ref" << std::endl; }
void f(int &&)
{ std::cout << "rval-ref" << std::endl; }
int main()
{
f(static_cast<const int &>(3));
return 0;
}
Casting the prvalue 3
to const int &
ensures that the lvalue-overload of f
is chosen.
In most contexts, you get this rvalue-to-lvalue modification automatically, simply by assigning to a variable:
int a = 3;
When you use a
after this line, it will be an lvalue. This is true even when a
is declared as rvalue reference:
int &&a = 3;
Here, too, a
becomes an lvalue (basically because it "has a name").
The only situation where I can imagine an explicit cast to have any relevant effect is my first example above. And there, when dealing with prvalues like 3
or temporaries returned from function calls by copy, the only legal cast is to const-reference (a non-const-reference is not allowed to bind to a prvalue).
回答2:
The solution to prevent an object to be moved is to make the move constructor of the object private, this way the object can't be moved but can be copied.
Example with move:
enter code here
#include <iostream>
class A {
public:
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n";}
A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; }
};
int main(int argc, const char * argv[])
{
A firsObject;
A secondObject = std::move(firsObject);
return 0;
}
Example with move disabled:
#include <iostream>
class A {
public:
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n";}
private:
A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; }
};
int main(int argc, const char * argv[])
{
A firsObject;
A secondObject = std::move(firsObject);
return 0;
}
回答3:
template<class T>
T& unmove(T&& t)
{
return t;
}
This will change the value category of the argument expression to an lvalue, no matter what it was originally.
void f(const int&); // copy version
void f(int&&); // move version
int main()
{
int i = ...;
f(42); // calls move version
f(move(i)); // calls move version
f(i); // calls copy version
f(unmove(42)); // calls copy version
f(unmove(move(i))); // calls copy version
f(unmove(i)); // calls copy version
}
来源:https://stackoverflow.com/questions/17543093/does-the-inverse-of-stdmove-exist