T&&工作?

时间:2013-09-08 23:32:59

标签: c++ c++11

我的理解不正确。我认为行动的重点是强迫T&&而不是T或T&超载。签名是

  

template typename remove_reference::type&& move (T&& arg) noexcept;

我还认为T&&和T&是一回事除了表示引用超出范围。根据我的理解,图像中的代码应该是安全的。

rv.append将创建一个新副本(将超出范围)或重用超出范围的rv。我认为实现是一个副本,因为移动就在那里。然后它再次追加,然后移动。当它返回时我想,因为它是对临时的引用,它不知道临时来自何处,应该将它复制到堆栈上postpone its lifetime

但是我不正确,修复程序写在图像中。为什么不这样做?是T&&像我想的那样通过引用传递?关于Rvalue参考,我还应该知道什么?

我也不明白this example中的std::unique_ptr<T> make_unique1(U&& u)如何调用两个不同的函数

enter image description here

3 个答案:

答案 0 :(得分:4)

  

rv.append将创建一个新副本(超出范围)或重用超出范围的rv。

不,它会修改rv本身,没有复制。这是一个修改rv的成员函数调用。

  

我认为实现是一个副本,因为移动就在那里。

不,当调用rv.append()时,它不会受到结果后发生的其他调用的影响,只会在std::string::append(const char*)上调用rv

  

然后它会再次追加,然后再移动。当它返回时我想,因为它是对临时的引用,它不知道临时来自何处,应该将它复制到堆栈上并推迟它的生命周期。

不,std::move只是将rv转换为std::string&&,没有任何魔法可以将任何内容复制到堆栈中。返回值是绑定到rv的rvalue-reference,它是绑定到meow()返回的临时值的rvalue-reference。然后在函数外部const std::string&绑定到同一个临时,然后在分号处临时超出范围,留下r作为悬空引用。

答案 1 :(得分:1)

右值引用有一个名称,因此它本身就是一个左值。 (这个想法是,如果你能够通过一个名称来引用一个对象,那么隐藏它就可能是不安全的,因为它的状态在移动后大多是未定义的。)

string&& join(string&& rv, const char* ptr) {
    // rv is an lvalue here
    rv.append(", "); // modifying rv
    rv.append(ptr);  // modifying again
    return move(rv); // move required because rv is an lvalue
}

返回传递的第一个参数的右值引用。从rvjoin的返回值没有副本,因为返回类型是引用,并且该引用的类型与表达式move(rv)的类型匹配。

join的返回类型是xvalue,它是一个glvalue和一个rvalue。因此它直接绑定到const lvalue ref r(不涉及副本)。

meow()返回的临时值持续到完整表达式const string& r = join(meow(), "purr");结束。由于它的生命周期没有延长,它被破坏,r成为悬挂参考。

答案 2 :(得分:1)

如你所说,T&&是一个类似于T&的引用,因此返回对局部变量的rvalue引用与返回对局部变量的常规引用相同,在本例中都是本地变量当函数退出并且您将获得无效引用时,将销毁变量(或在这种情况下是临时的)。 Lifetime扩展没有帮助,因为只有函数返回值临时绑定的生命周期才会延长,直到函数退出。

返回string值会修复此问题,因为返回值将从您使用move(rv.append(", ").append(ptr))创建的本地/临时变量中移动构造(作为新对象)。这样,当临时被破坏时,您返回的对象将不受影响。

另外一条评论,您的加入函数应按值rv取值,而不是通过右值参考(string rv而不是string&& rv)。除非移动构造函数非常昂贵(它不应该),性能将是相同的,您还可以在临时值上调用函数。我可以想到除了在移动构造函数中(或在模板函数中,它然后它实际上是一个通用引用)之外,你想要将变量声明为rvalue引用的极少数情况。