C++使用不同括号实现寿命扩展

16
我正在试图理解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";
}

输出

X::X()
X::~X()
Here1
X::X()
Here2
X::~X()
1个回答

18
自从 C++20 发布以来:
以下是此生命周期规则的例外情况:
- ... - 在使用直接初始化语法(圆括号)初始化的聚合体的引用元素中,临时绑定到引用的引用存在于包含初始化器的完整表达式的结束处,而不是列表初始化语法{大括号}。
``` struct A { int&& r; };
A a1{7}; // 可行,寿命得到扩展 A a2(7); // 合法,但是悬空引用 ```
那意味着对于 Y y2{X{}};,临时变量的生命周期将会被扩展为 y2(以及它的成员);而对于 Y y1(X{});,它不会,临时变量将会在完整表达式之后立即销毁。

13
我已经是一名C++程序员将近15年了,但我无法完全解释为什么有这么多极其微妙的初始化语法。这到底是怎么回事。 - Silvio Mayolo
3
@SilvioMayolo 即使是使用C++超过15年的人也难以理解其中的差异。这主要是由于该语言在保持向后兼容性的同时不断发展演变。一些语法/语义来自C,一些来自早期的C++标准(以及之前的草案标准)。C++11引入了语法/语义来帮助解决困扰(例如最令人烦恼的解析),并更好地支持新的语言特性(如右值引用等)。C++17及以后进一步进行了调整... - Peter
又是一个理由说明为什么推荐使用花括号初始化。 - digito_evo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接