为什么类构造函数为其成员生成析构函数?

Why class constructor generates destructors for its members?

本文关键字:析构函数 成员 构造函数 为什么      更新时间:2023-10-16

让我们从热身开始。

我创建了一个类模板,如果不激活编译器,其析构函数就无法实例化static_assert

文件: M.hpp

template <typename T>
struct M
{
M(){}
~M()
{
static_assert(sizeof(T) == 0, "no type can pass this");
}
};

接下来,我以两种不同的方式使用这个类:在堆上分配它并在堆栈上分配它:

文件主.cpp

#include "M.hpp"
int main()
{
M<int> *pmi = new M<int>(); // does compile
M<int> mi;                  // doen't compile
}

将其分配给堆M<int> *pmi = new M<int>();工作。之所以如此,因为我们只使用构造函数,不需要析构函数。类模板隐式实例化的规则说:

。除非在程序中使用该成员,否则不会实例化...

在堆栈M<int> mi;上分配它不起作用,因为编译器肯定需要实例化析构函数。

到目前为止一切顺利,明确的规则。

让我们进入正题。

我写了另一个使用M作为成员的类:

文件 X.cpp

#include "M.hpp"
struct X
{
X() = default;
~X() = delete;
private:
M<int> m_;
};

我故意删除了析构函数,因为我不希望它以任何方式干扰我的实验。 构造函数是默认的,在我的理解中,它应该只生成M<int>的构造函数,它的唯一成员,并调用它。 令我惊讶的是,情况并非如此。X()还尝试生成M<int>的析构函数:

文件主.cpp

#include "X.hpp"
int main()
{
X* px = new X();
}

这是我从编译器中得到的:

$ g++ -std=c++17 main.cpp
In file included from X.hpp:1,
from main.cpp:1:
M.hpp: In instantiation of ‘M<T>::~M() [with T = int]’:
X.hpp:5:3:   required from here
M.hpp:7:29: error: static assertion failed: no type can pass this
static_assert(sizeof(T) == 0, "no type can pass this");

问题是:为什么在实例化默认构造函数期间,如果不需要成员类模板的析构函数,编译器会尝试实例化它?如果确实需要,您能否指出我说明的文档?

X的构造函数可能会调用其成员子对象的析构函数,原因很明显:如果在构造过程中发生异常,则必须销毁所有已成功构造的内容。

10.9.2 初始化基和成员

12 在非委托构造函数中,可能会调用类类型的每个潜在构造子对象的析构函数 (15.4(。[注意:此规定确保在引发异常时可以为完全构造的子对象调用析构函数(18.2(。

http://eel.is/c++draft/class.base.init#12