C++ Lifetieme 带有不同括号的扩展

use*_*729 16 c++ lifetime temporary-objects

我试图理解 C++ 中的生命周期延长保证。有人可以解释为什么下面不同类型括号的使用在调用临时对象析构函数时会产生不同的结果吗?

#include <iostream>
struct X  {
    X() { 
        std::cout << __PRETTY_FUNCTION__ <<"\n";
    }
    ~X() {
        std::cout << __PRETTY_FUNCTION__ <<"\n";
    }
};

struct Y {
    X &&y;
};
int main() { 
    Y y1(X{});    
    std::cout << "Here1\n";
    Y y2{X{}};
    std::cout << "Here2\n";
}
Run Code Online (Sandbox Code Playgroud)

输出

X::X()
X::~X()
Here1
X::X()
Here2
X::~X()
Run Code Online (Sandbox Code Playgroud)

son*_*yao 18

C++20起:

此生命周期规则有以下例外情况:

  • ...

  • 到使用直接初始化语法(括号)初始化的聚合的引用元素中的引用的临时绑定一直存在,直到包含初始化程序的完整表达式结束为止,这与列表初始化语法{大括号}相反。

    struct A
    {
        int&& r;
    };
    
    A a1{7}; // OK, lifetime is extended
    A a2(7); // well-formed, but dangling reference
    
    Run Code Online (Sandbox Code Playgroud)

这意味着对于Y y2{X{}};, 临时对象的生命周期将延长为y2(及其成员);而对于Y y1(X{});它不会,临时将在完全表达后立即被销毁。

  • 我已经成为一名 C++ 程序员近 15 年了,我无法完全解释为什么有这么多初始化语法,而且差异极其细微。甚至什么。 (13认同)
  • @SilvioMayolo 即使使用 C++ 超过 15 年的人也很难理解这些差异。原因很大程度上是历史性的,因为该语言在不断发展的同时又保留了向后兼容性。一些语法/语义保留自 C,另一些则保留自早期 C++ 标准(以及之前的标准草案)。C++11 引入了语法/语义来帮助解决挫败感(例如最令人烦恼的解析)并更好地支持新的语言功能(例如右值引用等)。C++17 及后来的进一步调整... (3认同)