当一个类有一个简单的构造函数和/或一个普通的析构函数时,C ++标准定义了一些非常具体的行为。
例如,根据标准的§3.8/ 1:
类型
T
的对象的生命周期在以下时间结束:- 如果
T
是具有非平凡析构函数(12.4)的类类型,则析构函数调用开始,或- 重用或释放对象占用的存储空间。
所以,
虽然这个例子可能不是最好的例子,但它表明行为的差异可能是至关重要的(UB /非UB),无论对象是否具有琐事可破坏性。
标准的第12.4 / 3条规定,如果隐含地定义,而非虚拟的,并且如果所有基类和班级T
的成员是可以轻易破坏的。
在我的(谦虚)体验中,我从未在编译器生成的代码方面看到任何差异:
所以,我的问题是:
我的问题与标准无关(请不要回答标准说明什么是微不足道的ctor / dtor,因此用户定义的ctor / dtor不是),而是编译器处理用户定义的ctor / dtor的方式与琐碎的ctor / dtor相比,编译代码的行为可以改变(或不改变)的方式。
答案 0 :(得分:1)
你比我更了解标准,但是根据你提供的信息,标准定义了一个简单的析构函数,但它没有定义一个空的析构函数,这会使这个问题有点误导。因此,一个简单的析构函数是编译器可以优化的特殊情况,虽然空构造函数对我们有意义,但编译器编写者不必考虑它。
浏览一些SO链接:
要回答你的第二个问题,一旦你的ctor非空,这不是微不足道的。你得到的最接近的是一个空的ctor / dtor,你仔细阅读标准已经告诉你,这并没有被定义为微不足道。
TL; DR:该标准定义了一个简单的dtor,但不是空的dtor。智能编译器可以选择注意它是用户定义的空白并将其视为微不足道,但标准不需要任何此类考虑。
答案 1 :(得分:1)
用户定义的空ctor / dtor以何种方式可以或不可以被视为关于编译器代码生成,优化,权衡等的平凡的ctor / dtor ...
如果没有内联构造函数/析构函数,那么编译器可能(取决于链接时优化)必须向它们发出调用,即使它们是无操作。
例如,以下代码:
struct Struct {
Struct();
~Struct();
};
int main() {
Struct s;
}
编译为(启用优化):
main:
subq $24, %rsp
leaq 15(%rsp), %rdi
call Struct::Struct()
leaq 15(%rsp), %rdi
call Struct::~Struct()
xorl %eax, %eax
addq $24, %rsp
ret
请注意,仍然存在对构造函数和析构函数的调用,即使在单独的文件中我可以将它们定义为空函数。
但是,如果您已经定义了这些定义:
struct Struct {
Struct() {}
~Struct() {}
};
Struct foo() {
return Struct{};
}
然后编译器可以(并且如果它不完全吮吸)将它们视为琐碎的构造函数/析构函数:
foo():
movq %rdi, %rax
ret
在该示例中,任何构造函数/析构函数调用都已完全优化,生成的代码与Struct
的定义简单struct Struct {};
相同。
与用户定义的非空ctor / dtor相同的问题;应该遵循ctor / dtor中实现的代码遵循哪些规则来将它们视为微不足道的。
这种取决于。同样,如果构造函数/析构函数没有内联,那么编译器可能仍然必须向它们发出调用,在这种情况下,它们并不是那么简单。
但是,如果优化器可以完全优化它们(例如,如果它们只包含for (int x = 0; x < 1000; ++x);
,那么内联非空构造函数/析构函数可能仍然是“平凡的”,那么这是无用的代码,可以是优化了他们实际上是空的。
但如果他们做了有用的工作,而这些工作不能被优化掉,那么他们就不会像琐碎一样。他们会跑。他们必须。