大括号的类型如何影响 C++ 中的对象生命周期?
How can the type of braces influence object lifetime in C++?
我的一个朋友给我看了一个 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";
}
在 GCC 中它打印:
A()
~A()
---
A()
---
A()
---
~A()
~A()
https://gcc.godbolt.org/z/ce3M3dPeo
因此在情况 y 和 z 中 A
的生命周期延长了。
在Visual Studio中结果不同:
A()
~A()
---
A()
---
A()
~A()
---
~A()
所以A
的生命周期只有在y的情况下才会延长。
能否请您解释一下为什么大括号的类型会影响对象的生命周期?
Gcc 是正确的。只有在聚合初始化中使用列表初始化语法(即使用大括号)时,临时对象的生命周期才会 extended。
(since C++20) a temporary bound to a reference in a reference element of an
aggregate initialized using direct-initialization syntax (parentheses)
as opposed to list-initialization syntax (braces) exists until the end
of the full expression containing the initializer.
struct A {
int&& r;
};
A a1{7}; // OK, lifetime is extended
A a2(7); // well-formed, but dangling reference
(强调我的)
otherwise, if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted, designated initializers are not allowed, a temporary bound to a reference does not have its lifetime extended, there is no brace elision, and any elements without an initializer are value-initialized. (since 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";
}
在 GCC 中它打印:
A()
~A()
---
A()
---
A()
---
~A()
~A()
https://gcc.godbolt.org/z/ce3M3dPeo
因此在情况 y 和 z 中 A
的生命周期延长了。
在Visual Studio中结果不同:
A()
~A()
---
A()
---
A()
~A()
---
~A()
所以A
的生命周期只有在y的情况下才会延长。
能否请您解释一下为什么大括号的类型会影响对象的生命周期?
Gcc 是正确的。只有在聚合初始化中使用列表初始化语法(即使用大括号)时,临时对象的生命周期才会 extended。
(since C++20) a temporary bound to a reference in a reference element of an aggregate initialized using direct-initialization syntax (parentheses) as opposed to list-initialization syntax (braces) exists until the end of the full expression containing the initializer.
struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference
(强调我的)
otherwise, if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted, designated initializers are not allowed, a temporary bound to a reference does not have its lifetime extended, there is no brace elision, and any elements without an initializer are value-initialized. (since C++20)