如何在异常上从构造函数中调用基类析构函数?

时间:2015-09-25 03:25:47

标签: c++ c++11 exception constructor destructor

我有一些从Daughter1继承的课程Daughter2Mother

class   Mother
{
public:
    Mother(); // Empty constructor.
    virtual ~Mother(); // Delete common daughter's stuff.

protected:
    // Common stuff of each daughter.
};

每个女儿班的常见东西都有相同的删除方法,所以母亲负责。但是,它们的初始化不一样,所以它们分别位于各自的女儿的构造函数中:

class   Daughter1 : public Mother
{
public:
    Daughter1(); // Initialize mother's stuff
    ~Daughter1();
};

class   Daughter2 : public Mother
{
public:
    Daughter2(); // Initialize mother's stuff in a different way than Daughter1
    ~Daughter2();
};

问题是:有时,子构造函数无法加载其内容并抛出异常。当我宣布像这样的女儿时:

Daughter1   daughter;

构造函数抛出异常,它调用母亲的析构函数,它试图在没有初始化的情况下删除它的东西,这不可避免地导致分段错误。

避免这种麻烦的最佳方法是什么?

我的大多数东西都是由指针组成的,所以我知道我可以简单地将它们初始化为母版本构造函数中的nullptr,然后在析构函数中尝试删除之前检查它们,但它只适用于指针和我&# 39;我正在寻找全球解决方案。

3 个答案:

答案 0 :(得分:2)

您不应该在Mother析构函数中删除未初始化的指针 - 只需更改指向智能指针的指针,例如std::unique_ptr他们只有在需要时才delete

更一般地说,~Mother仅在Mother基类完成构造时被调用,然后每个成员变量应处于任何析构函数可以安全运行的状态。对于像doubleint这样的类型,没有什么可以破坏,所以不需要做任何事情。使用智能指针而不是原始指针,或标准容器/ std::string而不是您自己的hackery。更一般地说,寻找或制作遵循RAII原则的课程,以确保他们正确地清理自己。

  

只需在母版构造函数中将它们初始化为nullptr并在析构函数中尝试删除之前检查它们

FWIW,没有必要在delete之前检查它们delete nullptr是一个(安全)无操作。换句话说,你添加的任何支票都是多余的,当指针不是nullptr时可能会浪费时间。

答案 1 :(得分:2)

母亲的东西应该由母亲的构造者初始化,而不是女儿的。将所有必需的初始化参数作为构造函数参数传递给Mother的构造函数,而不是(假设您正在执行)使用子构造函数中的赋值语句。

对母亲进行编码,以便母亲可以自行构建和销毁,而不依赖任何派生类的活动。

Daughter1 daughter();声明一个函数,没有构造函数被调用。

答案 2 :(得分:1)

另一种可能的解决方案是使用静态方法创建子对象(如here)而不是真正的构造函数。在这种情况下,你可以使构造函数非常轻量级和非抛出,只需将所有复杂的逻辑放入这些静态方法中。