C++ R值和L值的输出不同。为什么?

C++ R值和L值的输出不同。为什么?,c++,c++11,rvalue-reference,perfect-forwarding,C++,C++11,Rvalue Reference,Perfect Forwarding,有人能解释为什么R值的输出与L值不同吗 #include <iostream> #include <vector> using namespace std; template<typename Ct> struct ct_wrapper { Ct&& ct; // R or L ref explicit ct_wrapper(Ct&& ct) : ct(std::forward<Ct>

有人能解释为什么R值的输出与L值不同吗

#include <iostream>
#include <vector>
using namespace std;

template<typename Ct>
struct  ct_wrapper {
    Ct&& ct; // R or L ref
    explicit ct_wrapper(Ct&& ct) 
      : ct(std::forward<Ct>(ct)) { std::cout <<  this->ct[1];};
};

int main() {

    // L-val
    vector<int> v{1,2,3};
    ct_wrapper<vector<int>&> lv(v);
    cout << endl << lv.ct[0] << lv.ct[1] << lv.ct[2] << endl;

    // R-val
    ct_wrapper<vector<int>&&> rv(vector<int>{1,2,3});
    cout << endl << rv.ct[0] << rv.ct[1] << rv.ct[2] << endl;
}
回答

它在我和Johannes Schaub的聊天中被掩埋了,所以我把它放在这里


当临时向量初始化r-value-ref成员变量
rv.ct
时,临时生存期不会延长,因为存在一个特殊的异常:[class.temporary]p5:“在构造函数的ctor初始化器(12.6.2)中,临时绑定到引用成员,直到构造函数退出。”因为您的会员只是一个参考人。在第二种情况下,在本地
rv
变量定义完成后,它引用的对象已经死了。因此,
cout
中后面的访问是未定义的行为

因为你的会员只是一个推荐人。在第二种情况下,在本地
rv
变量定义完成后,它引用的对象已经死了。因此,
cout
中后面的访问是未定义的行为

您的程序有未定义的行为,因为您正在访问一个悬空引用。临时向量在其出现的完整表达式末尾被销毁,但您保留了对它的引用。

您的程序具有未定义的行为,因为您正在访问一个悬空引用。临时向量在其出现的完整表达式末尾被销毁,但您保留了对它的引用。

在r值情况下,您将临时向量绑定到引用。当您到达最后一个输出语句时,它将已经消失。

在r值的情况下,您将临时值绑定到引用。当您看到最后一条输出语句时,它已经消失了。

+1(以及所有其他语句),但我仍然感到困惑。我认为当临时绑定到r-value ref时,它的生存期会延长到r-value变量的生存期。不我们仍然有
rv.ct
@LeonidVolnitsky有一个特殊的例外(因为编译器不可能正确地实现这一点):[class.temporary]p5:“临时绑定到构造函数的ctor初始值设定项(12.6.2)中的引用成员,直到构造函数退出为止。”(我想说的是,引用不一定是临时的,而是临时的,但我在标准中看不到这种区别。)@hvd对。实际上,这种区别不是在子句class.temporary中进行的。该子句指的是表达式直接具有该属性的情况。(当标准中的文本显示“创建了一个临时prvalue…”,然后右值直接携带该临时属性)。其他规则指的是临时对象,而不是以这种方式标记的表达式,因此需要始终仔细阅读所包含的上下文以了解其含义(IMHO,这里的规范非常差,可以更清楚地说明,请参阅)。感谢您的澄清,很高兴知道我不是唯一一个弄糊涂的人。:)所以它毕竟更简单,初始化器
std::forward(ct)
不是临时的(在[class.temporary]的上下文中)@LeonidVolnitsky:这真的没有那么令人困惑:引用变量是
ct
,并且该变量只在构造函数的持续时间内存在,但我仍然感到困惑。我认为,当临时绑定到r-value ref时,它的生存期会延长到r-value变量的生存期。否?并且我们仍然有
rv.ct
@LeonidVolnitsky,有一个特殊的例外(因为编译器不可能获得正确的结果):[class.temporary]p5:在构造函数的ctor初始值设定项(12.6.2)中,临时绑定到引用成员的情况会一直存在,直到构造函数退出。”(我想说的是,引用不是绑定到临时成员,而是绑定到临时成员的引用,但我在标准中看不到这种区别。)@hvd正确。实际上,在子句class.temporary中没有进行区分。该子句指的是表达式直接具有该属性的情况。(当标准中的文本表示“创建了临时prvalue…”,则右值直接带有该临时属性)。其他规则指的是临时对象,而不是以这种方式标记的表达式,因此需要始终仔细阅读所包含的上下文以了解其含义(IMHO,这里的规范非常差,可以更清楚地说明,请参阅)。感谢您的澄清,很高兴知道我不是唯一一个弄糊涂的人。:)所以它毕竟更简单,初始化器
std::forward(ct)
不是临时的(在[class.temporary]的上下文中)@LeonidVolnitsky:这真的没有那么令人困惑:引用变量是
ct
,并且该变量只在构造函数期间有效。
2
123
2
003