Does the inverse of std::move exist? [duplicate]

自闭症网瘾萝莉.ら 提交于 2019-12-19 09:46:44

问题


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::movethat 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!