大括号的类型如何影响 C++ 中的对象生命周期?

Fed*_*dor 33 c++ initialization object-lifetime temporary-objects c++20

我的一个朋友给我看了一个 C++20 程序:

#include <iostream>

struct A
{
    A() {std::cout << "A()\n";}
    ~A() {std::cout << "~A()\n";}
};

struct B
{
    const A &a;
};

int main()
{
    B x({});
    std::cout << "---\n";
    B y{{}};
    std::cout << "---\n";
    B z{A{}};
    std::cout << "---\n";
}
Run Code Online (Sandbox Code Playgroud)

在 GCC 中,它打印:

A()
~A()
---
A()
---
A()
---
~A()
~A()
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/ce3M3dPeo

因此,A在 y 和 z 情况下,的寿命会延长。

在 Visual Studio 中,结果是不同的:

A()
~A()
---
A()
---
A()
~A()
---
~A()
Run Code Online (Sandbox Code Playgroud)

所以A只有在 y 的情况下,的寿命才会延长。

你能解释一下为什么大括号的类型会影响对象的生命周期吗?

son*_*yao 28

gcc 是正确的。只有在聚合初始化中使用列表初始化语法(即使用大括号)时,临时对象的生命周期才会延长

(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)

对于直接初始化

(强调我的)

否则,如果目标类型是(可能是 cv 限定的)聚合类,则按照聚合初始化中的描述对其进行初始化,除了允许缩小转换、不允许指定的初始值设定项、指向引用的临时绑定不会延长其生命周期,没有大括号省略,任何没有初始化器的元素都是值初始化的。(C++20 起)

  • IIRC 的意图(在 `()` 后面不延长生命周期)是模仿用户提供的构造函数的行为,它不能延长生命周期,因为它们间接地(从引用参数)初始化引用成员,而生命周期扩展不会用另一个引用初始化一个引用时传播。 (5认同)