- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
众所周知,在某些情况下,编译器可能会忽略对复制构造函数的调用。但是,标准明确指出,编译器只能自由更改运行时行为(调用或不调用复制构造函数),但执行翻译时就像调用复制构造函数一样。特别是,编译器会检查是否有有效的复制构造函数可以调用。
我遇到了这样一种情况,即可能会省略析构函数调用,但编译器在是否需要存在有效析构函数方面存在差异。
这是一个完整的示例,展示了此问题如何发生以及编译器的行为有何不同。
template <typename T>
struct A {
~A() { (void) sizeof(T); }
};
struct B; // defined elsewhere.
struct C {
A<B> x, y;
~C(); // defined in a TU where B is complete.
};
int main() {
C c;
}
编译时main()
编译器生成 C
的默认构造函数。此构造函数默认首先初始化 x
然后 y
.如果在 y
期间抛出异常 build ,然后x
必须销毁。生成的代码如下所示:
new ((void*) &this->x) A<B>; // default initializes this->x.
try {
new ((void*) &this->y) A<B>; // default initializes this->y.
}
catch (...) {
(this->x).~A<B>(); // destroys this->x.
throw;
}
知道 A<B>
的默认构造函数是微不足道的(并且不会抛出),在 as-if 规则下,编译器可能会将代码简化为:
new ((void*) &this->x) A<B>; // default initializes this->x.
new ((void*) &this->y) A<B>; // default initializes this->y.
因此,无需调用 ~A<B>()
. (实际上,编译器甚至可以删除上面的两个初始化,因为 A<B>
的构造函数是微不足道的,但这对于本次讨论并不重要。)
问题是:即使对析构函数的调用可能被省略,编译器是否应该验证有效的析构函数是否可用?我在标准中找不到任何可以澄清问题的内容。谁能提供相关的报价?
如果编译器决定不翻译 ~A<B>()
(就像 gcc 和 Visual Studio 一样)然后编译成功。
但是,如果编译器决定翻译 ~A<B>()
无论如何(就像 clang 和 icc 一样),然后它会引发一个错误,因为这里 B
是不完整的类型,无法取其大小。
最佳答案
我不认为这是标准规定的。如果 ~A<B>
被实例化然后它是格式错误的并且需要诊断。正如你所说,如果构建 y
抛出,然后 x
必须销毁。
但是,构造 y
永远不能抛出,因此可以说永远不会要求析构函数的定义存在(15.2/2、14.7.1/3)。
关于c++ - 编译器对析构函数省略的自由度是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23184712/
我是一名优秀的程序员,十分优秀!