未使用的默认成员初始化器如何改变 C++ 中的程序行为?
Posted
技术标签:
【中文标题】未使用的默认成员初始化器如何改变 C++ 中的程序行为?【英文标题】:How unused default member initializer can change program behavior in C++? 【发布时间】:2021-09-22 09:01:05 【问题描述】:请考虑这个简短的代码示例:
#include <iostream>
struct A
A() std::cout << "A() ";
~A() std::cout << "~A() ";
;
struct B const A &a; ;
struct C const A &a = ; ;
int main()
B b();
std::cout << ". ";
C c();
std::cout << ". ";
GCC 在此处打印 (https://gcc.godbolt.org/z/czWrq8G5j)
A() ~A() . A() . ~A()
意味着A
-object 初始化引用在b
中的生命周期很短,但在c
中生命周期延长到作用域结束。
结构B
和C
之间的唯一区别在于默认成员初始化程序,它在main() 中未使用,但行为仍然不同。你能解释一下原因吗?
【问题讨论】:
如果它真的打印出来那么它是编译器中的一个错误。 又一票投给 GCC 错误,代码甚至无法在 MSVC 或 clang 中编译 @AlanBirtles:使用 MSVC Demo 编译。它是 C++20 功能(使用()
进行聚合初始化),clang 尚不支持,请参阅 compiler_support(聚合的括号初始化)。
@Jarod42,问题应该加C++20标签吗?
是的,很好
【参考方案1】:
C c(...);
是直接初始化的语法。重载解析将从C
的构造函数中找到匹配项:移动构造函数可以通过从 临时实现的
C
来调用。 是值初始化,它将使用默认的成员初始化程序。因此,默认成员初始化程序没有被使用。从 C++17 开始,不需要移动构造函数,
直接初始化变量
c
;在这种情况下,c.a
直接绑定到临时的A
,并且生命周期会延长,直到 C
销毁。
B
不是默认可构造的,因此重载决议找不到匹配项。相反,从 C++20 开始使用聚合初始化 - 在此之前它将是格式错误的。 C++20 特性的设计是不改变以前有效程序的行为,因此聚合初始化的优先级低于移动构造函数。
与C
的情况不同,临时A
的生命周期不会延长,因为带括号的初始化列表是一个例外情况。如果您使用花括号,它将被扩展:
B b;
【讨论】:
但B
的行为不像B()
Demo
看起来是正确的解释。在此基础上,我消除了C
-object 默认初始化,现在结果一致:gcc.godbolt.org/z/3GxE3qqh5Thanks
()
表单不会延长临时对象的生命周期。见eel.is/c++draft/class.temporary#6.10
@T.C.谢谢。那么编译器的行为是正确的。以上是关于未使用的默认成员初始化器如何改变 C++ 中的程序行为?的主要内容,如果未能解决你的问题,请参考以下文章