为什么C++中类字段的默认初始化需要析构函数调用?
请帮我完成这个程序:
struct U {
U(int *) noexcept;
private:
~U() noexcept;
};
struct B {
B();
~B();
U v; //ok
U w{nullptr}; //ok
U u = nullptr; //error
};
这里 structU有一个私有的析构函数,只是为了演示析构函数并不是真正被编译器调用的,也是为了简化代码的长度。
而且structB只声明了一个默认的构造函数和析构函数,所以编译器不会在这个翻译单元中生成它们。
structB也有 3 个字段:v,w和u. v和w字段没有问题,但是对于字段u,编译器会发出有关无法访问的析构函数的错误U:
error: 'U::~U()' is private within this context
13 | U u = nullptr; //error
演示:https : //gcc.godbolt.org/z/YooGe9xq6
问题是:
- 如果
B::B()没有在这个翻译单元中编译,为什么要考虑字段默认初始化? - 错误是因为为
u字段的初始化创建了一个临时对象吗?(没有强制复制省略?) - 那么
u和wcase 有什么区别呢?
回答
如果 B::B() 没有在这个翻译单元中编译,为什么要考虑字段默认初始化?
因为成员初始化是类定义的一部分。因此,类定义本身是无效的,而不必涉及其构造函数的定义。在标准中,您可以从[class.mem.general]开始并遵循brace-or-equal-initializer,这最终需要一个有效的“沼泽标准”赋值表达式。
错误是因为为 u 字段的初始化创建了一个临时对象吗?(没有强制复制省略?)
是的,你的 Godbolt 链接中的编译器错误很清楚:
<source>:13:11: error: temporary of type 'U' has private destructor
U u = nullptr; //error
请参阅为什么 C++ 中的强制 RVO 需要公共析构函数?解释为什么强制复制省略不适用(谢谢@NathanPierson!)
那么 u 和 w 情况有什么区别呢?
w直接初始化而无需事先创建临时文件,因此创建它可以正常工作,因为表达式中没有任何内容试图调用U. 显然, 的任何定义B::~B()仍然会在 上失败w,但这已经超出了重点。