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

时间:2018-10-10 22:42:01

标签: c++

让我们从热身开始吧。

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

文件:M.hpp

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

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

文件main.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>();上分配它是可行的。之所以如此,是因为我们仅使用构造函数而无需析构函数。类模板隐式实例化say的规则:

  

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

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

到目前为止,一切都很清楚。

我们要点了。

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

文件X.cpp

#include "M.hpp"

struct X
{
    X() = default;
    ~X() = delete;

private:
    M<int> m_;
};

我故意删除了析构函数,因为我不希望它干扰我的实验。 默认构造函数,根据我的理解,该构造函数仅应生成M<int>的构造函数(唯一的成员)并调用它。 令我惊讶的是,事实并非如此。 X()还将尝试生成M<int>的析构函数:

文件main.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");

问题是:为什么在默认构造函数的实例化过程中,编译器尝试为成员类模板实例化析构函数(如果不需要)?如果确实需要它,您能指出我指出的文件吗?

1 个答案:

答案 0 :(得分:3)

您的X的构造函数有可能出于明显的原因而调用其成员子对象的析构函数:如果在构造过程中发生异常,则必须破坏已经成功构造的所有事物。

>
  

10.9.2初始化基础和成员

     

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

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