c++ - 为什么 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
那么 case和w
case有什么区别呢?
解决方案
如果 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
,但这已经超出了重点。
推荐阅读
- android - 避免使用 android 在 Firebase Firestore 中出现重复值
- c++ - 在笛卡尔二维空间中找到每个象限中的最近点
- excel - 我想从图表中排除 0 的公司
- python - 根据选择将功能组织成模块
- android - Webview 的 loadData() 在 android 10.0 (Q) 中不起作用
- c# - 使用 DataGridViewCheckBoxColumn 更新 DatagridView
- python - TypeError: 'bool' 对象在尝试使用 unlink() 时没有属性 '__getitem__'
- powershell - 两个 Invoke-Command 同时
- log4j - IIB 中出现无法定位消息节点“Log4jLoggingPlugin”错误?
- r - 如何使用 R 中的条件行填充值?