【问题标题】:Why class constructor generates destructors for its members? [duplicate]为什么类构造函数为其成员生成析构函数? [复制]
【发布时间】:2019-03-15 22:16:03
【问题描述】:

让我们从热身开始吧。

我创建了一个类模板,如果没有编译器激活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&lt;int&gt; *pmi = new M&lt;int&gt;(); 有效。因为我们只使用构造函数而不需要析构函数。类模板隐式实例化规则say

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

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

到目前为止一切顺利,规则清晰。

让我们进入正题。

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

文件 X.cpp

#include "M.hpp"

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

private:
    M<int> m_;
};

我故意删除了析构函数,因为我不希望它干扰我的实验。 构造函数是默认的,在我的理解中应该只生成 M&lt;int&gt; 的构造函数,它的唯一成员,然后调用它。 令我惊讶的是,事实并非如此。 X() 也尝试生成M&lt;int&gt; 的析构函数:

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

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

【问题讨论】:

    标签: c++


    【解决方案1】:

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

    10.9.2 初始化基和成员

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

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

    【讨论】:

    • 我认为(也许我错了)如果可能的话,ctors 的默认实现是noexceptM 应该是这种情况,因此这里的X 也是如此。那么,如果不能抛出异常,为什么仍然可能调用 dtor?
    猜你喜欢
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 2015-04-28
    • 1970-01-01
    相关资源
    最近更新 更多