C++ 为什么类构造函数为其成员生成析构函数? 让我们从热身开始。

C++ 为什么类构造函数为其成员生成析构函数? 让我们从热身开始。,c++,C++,我创建了一个类模板,如果没有编译器激活static\u assert,它的析构函数就无法实例化: 档案:M.hpp 模板 结构M { M(){} ~M() { static_assert(sizeof(T)==0,“没有类型可以传递它”); } }; 接下来,我以两种不同的方式使用这个类:在堆上分配它和在堆栈上分配它: 文件main.cpp #包括“M.hpp” int main() { M*pmi=new M();//编译 M mi;//不编译 } 在堆上分配它M*pmi=newm()工作

我创建了一个类模板,如果没有编译器激活
static\u assert
,它的析构函数就无法实例化:

档案:M.hpp

模板
结构M
{
M(){}
~M()
{
static_assert(sizeof(T)==0,“没有类型可以传递它”);
}
};
接下来,我以两种不同的方式使用这个类:在堆上分配它和在堆栈上分配它:

文件main.cpp

#包括“M.hpp”
int main()
{
M*pmi=new M();//编译
M mi;//不编译
}
在堆上分配它
M*pmi=newm()工作。这是因为我们只使用构造函数,不需要析构函数。类模板隐式实例化的规则:

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

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

到目前为止,规则是好的、明确的

让我们开门见山吧。 我写了另一个类,它使用
M
作为成员:

文件X.cpp

#包括“M.hpp”
结构X
{
X()=默认值;
~X()=删除;
私人:
M_;
};
我故意删除了析构函数,因为我不想让它干扰我的实验。 构造函数是默认的,在我的理解中,它应该只生成
M
的构造函数,它是它唯一的成员,并调用它。 令我惊讶的是,事实并非如此
X()
还尝试生成
M
的析构函数:

文件main.cpp

#包括“X.hpp”
int main()
{
X*px=新的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");
$g++-std=c++17 main.cpp
在X.hpp:1中包含的文件中,
来自main.cpp:1:
M.hpp:在“M::~M()[with T=int]”的实例化中:
X.hpp:5:3:从这里开始需要
M.hpp:7:29:错误:静态断言失败:没有类型可以传递此消息
static_assert(sizeof(T)==0,“没有类型可以传递它”);

问题是:为什么在实例化默认构造函数的过程中,如果不需要,编译器会尝试实例化成员类模板的析构函数?如果确实需要的话,你能告诉我文件上的说明吗

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

10.9.2初始化基础和成员

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

我认为(也许我错了)如果可能的话,CTOR的默认实现是
noexcept
,这应该是
m
的情况,因此
X
也是如此。那么,如果不能抛出异常,为什么dtor仍有可能被调用呢?