简体   繁体   English

调用std :: move返回值-签名应该是什么

[英]Calling std::move on a return value - what should the signature be

Consider 考虑

class X
{
public:
    std::unique_ptr<int> m_sp;
    A m_a;

    A test1()
    {
        return std::move(m_a);
    }

    A&& test2()
    {
        return std::move(m_a);
    } 

    std::unique_ptr<int> test3()
    {
        return std::move(m_sp);
    }

    std::unique_ptr<int>&& test4()
    {
        return std::move(m_sp);
    }

    std::unique_ptr<int> test5()
    {
        return std::make_unique<int>(50);
    }
};

class A
{
public:
    A()
    {
        m_i = 1;
    }

    A(A&& other)
    {
        this->m_i = other.m_i;
        other.m_i = -1;
    }

    A& operator=(A&& other)
    {
        this->m_i = other.m_i;
        other.m_i = -1;
        return *this;
    }

    int m_i;
};

To exercise these classes 练习这些课程

X x;
A y;
y.m_i = 10;
y = x.test1();

X x2;
A y2;
y2.m_i = 10;
y2 = x2.test2();

both call A's move assignment but only in the test1 case do we call A's move constructor. 两者都调用A的move赋值,但仅在test1情况下才调用A的move构造函数。 Why is that? 这是为什么? Is it because as we cannot return a A&& (std::move will cast A to A&&, but test1 says it must return an A). 是因为我们无法返回A &&(std :: move会将A强制转换为A &&,但是test1说它必须返回A)。

In general, when one wants to move/transfer ownership of expensive member variables, do you want to specify the return to be an rvalue-reference (A&&) or an lvalue (A) type? 通常,当您想转移/转让昂贵的成员变量的所有权时,是否要将返回值指定为右值引用(A &&)或左值(A)类型?

It feels a little unnatural as if you aren't using member variables, you let RVO/NRVO do it's thing and just return an lvalue. 感觉好像有点不自然,好像您没有使用成员变量一样,您让RVO / NRVO做到了,只是返回一个左值。 Take in the case of unique_ptr, when you've got an automatic variable you have a signature like test5(), but if you have a variable, not suitable for RVO/NRVO, like a member varaible should test3 or test4's signature be preferred. 以unique_ptr为例,当您拥有一个自动变量时,您将拥有一个类似于test5()的签名,但是如果您拥有一个不适合RVO / NRVO的变量,例如一个成员变量,则应首选test3或test4的签名。

Interested to know. 有兴趣知道。

Thanks 谢谢

There's a semantic difference there. 那里有语义上的区别。 When you return an object like in 当您返回类似的对象时

A test1()
{
    return std::move(m_a);
}

std::unique_ptr<int> test3()
{
    return std::move(m_sp);
}

then you always move out of your member. 那么您总是会离开您的会员。 No matter whether the caller does something with the return value or not, you will have moved out of your X into a temporary. 无论调用方是否对返回值进行任何操作,您都将移出X到临时变量中。 Ownership lies no longer with you. 所有权不再与您同在。 The caller may take over the return value. 调用者可以接管返回值。 If the caller ignores the return value, the temporary will be destroyed anyways. 如果调用方忽略返回值,则无论如何都将销毁该临时对象。 If you return an rvalue-reference, on the other hand, like in 另一方面,如果您返回右值引用,例如

A&& test2()
{
    return std::move(m_a);
}

std::unique_ptr<int>&& test4()
{
    return std::move(m_sp);
}

you are simply offering the caller the opportunity to move from/take over ownership of the object. 您只是为呼叫者提供了从对象的所有权转移/接管的机会。 If the caller does not perform the move, your X will retain the ownership, the object will not be moved. 如果调用者不执行移动,则您的X将保留所有权,该对象将不会移动。

The crucial thing to understand is that, contrary to what the name suggests, std::move() does not actually perform a move. 要理解的关键是,与名称所暗示的相反, std::move()实际上并不执行移动。 It merely allows that a given object be moved from. 它仅允许移动给定的对象。 The actual move is performed by the move constructor or move assignment operator of the respective type. 实际移动由相应类型的移动构造函数或移动分配运算符执行。

So your answer is: it depends on what you want to express. 因此,您的答案是:这取决于您要表达的内容。 If you return an object, you're saying "I'm throwing this away, if you want it: it's over there". 如果您返回一个对象,则是在说:“如果需要,我会把它扔掉:它在那儿”。 If you return an rvalue reference, you're saying "that's the thing, now's your chance to take it, otherwise I keep it"… 如果返回右值引用,则表示“就是这样,现在有机会接受它,否则我会保留它”…

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM