Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 扩展临时';R值数据成员的生存期与聚合一起工作,但与构造函数不一起工作,为什么?_C++_C++11_Language Lawyer_Rvalue Reference_Object Lifetime - Fatal编程技术网

C++ 扩展临时';R值数据成员的生存期与聚合一起工作,但与构造函数不一起工作,为什么?

C++ 扩展临时';R值数据成员的生存期与聚合一起工作,但与构造函数不一起工作,为什么?,c++,c++11,language-lawyer,rvalue-reference,object-lifetime,C++,C++11,Language Lawyer,Rvalue Reference,Object Lifetime,我发现以下延长临时人员生命周期的方案是有效的,我不知道是否应该,但确实有效 struct S { std::vector<int>&& vec; }; int main() { S s1{std::vector<int>(5)}; // construct with temporary std::cout << s1.vec[0] << '\n'; // fine, temporary is al

我发现以下延长临时人员生命周期的方案是有效的,我不知道是否应该,但确实有效

struct S {
    std::vector<int>&& vec;
};

int main() {
    S s1{std::vector<int>(5)};      // construct with temporary
    std::cout << s1.vec[0] << '\n'; // fine, temporary is alive
}

为什么这对聚合有效?我认为这与构造函数是一个实际的函数调用有关,这是基于我读到的const-lvalue-refs。此外,有没有办法使后一种情况起作用

使用左值引用来处理类似情况时,会出现大量问题。我发现,如果我使用常量左值ref,它将无助于延长临时值的生存期,右值ref的规则是否相同?

TL;DR

聚合初始化可以用来延长临时构造函数的生命周期,用户定义的构造函数不能这样做,因为它实际上是一个函数调用

注意:在聚合初始化和延长绑定到它们的临时变量的寿命的情况下,
T常量和
T&
都适用



什么是聚合?


从语义上讲,上述内容相当于使用以下内容初始化我们的成员,只是在这种情况下,
A::A
A::b
只能通过
x.A
x.b
访问

std::string A::a { std::string {"abc"} };
int         A::b { 2 };

如果我们将
A::A
的类型更改为右值引用或常量左值引用,我们将直接将用于初始化的临时用法绑定到
x.A

右值引用和常量左值引用的规则表明,临时变量的生存期将延长到主机的生存期,这正是将要发生的事情



使用用户声明的构造函数进行初始化有何不同?

传递给
func
的临时变量不会因为有一个参数声明为右值/左值引用而延长其生存期。即使我们返回“相同”的引用,以便它在
func
之外可用,它也不会发生

这就是(2)的构造函数中发生的情况,毕竟构造函数只是用于初始化对象的“奇特函数”


12.2p5
临时对象
[class.Temporary]

引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生存期内持续存在,但以下情况除外:

  • 构造函数的ctor初始值设定项(12.6.2)中与引用成员的临时绑定将持续存在,直到构造函数退出

  • 函数调用(5.2.2)中引用参数的临时绑定将持续存在,直到包含该调用的完整表达式完成。

  • 函数返回语句(6.6.3)中返回值的临时绑定的生存期没有延长;在return语句的完整表达式末尾销毁临时表达式

    • 临时绑定到新初始值设定项(5.3.4)中的引用将持续,直到包含新初始值设定项的完整表达式完成

< > >强>注释> /强>:注意,通过<代码>新的t{} /Cube >的聚合初始化与前面提到的规则不同。<>“代码> const LValueRefs/Case>不能延长临时的生命周期”-HUH,这看起来像是滥用C++(它工作并不意味着它是正确的,它可能是未定义的行为)。临时变量的生存期延长规则与将临时变量绑定到引用有关,它们不区分左值引用和右值引用。第一句中的声明是可疑的,提供的测试过于简单。如果我没记错的话,标准中有一些有趣的条款,使这种情况与其他情况不同。就像“构造函数中的引用绑定不会延长生存期”。这里缺少构造函数意味着引用绑定直接由编译器完成,所以。。。这可能有用。当我考虑提出“生命周期链接”时,我研究了生命周期扩展规则,以便在通过助手函数转发临时表时绕过一些不必要的副本。这一切都是有意义的,谢谢。如果我正确地阅读了您的最后一个注释,如果您通过new使用聚合初始化,则临时对象的生存期不会得到延长(我假设,因为对象是非确定性分配的),对吗?@RyanHaining这是正确的。我正在考虑用一个更详细的问答回答为什么会这样。这是有趣的吗?我想这与编译器不知道临时生命何时结束有关。如果使用相同的右值ref的非constexpr量为
new
s,则该右值的生存期现在将非确定性地延长。这意味着有两个选项,一个是将右值ref移动到
新的
'd对象中,但是两个位置的右值地址会不同,更不用说这是一个移动构造函数,编译器不一定允许isert。另一种方法是将其保留在堆栈上,但新的d对象可能会比临时对象寿命长。但是,我可能会偏离这一点,如果你详细说明的话,我会感兴趣的。@Frunsi我在这里谈论的是新的与非新的分配。
struct S {                // (1)
  std::vector<int>&& vec;
};
struct A { std::string a; int b; };
A x { std::string {"abc"}, 2 };
std::string A::a { std::string {"abc"} };
int         A::b { 2 };
struct S {                    // (2)
    std::vector<int>&& vec;
    S(std::vector<int>&& v)
        : vec{std::move(v)}   // bind to the temporary provided
    { }
};
std::string&& func (std::string&& ref) {
  return std::move (ref);
}