我有一些从Daughter1
继承的课程Daughter2
和Mother
:
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;我正在寻找全球解决方案。
答案 0 :(得分:2)
您不应该在Mother
析构函数中删除未初始化的指针 - 只需更改指向智能指针的指针,例如std::unique_ptr
他们只有在需要时才delete
。
更一般地说,~Mother
仅在Mother
基类完成构造时被调用,然后每个成员变量应处于任何析构函数可以安全运行的状态。对于像double
和int
这样的类型,没有什么可以破坏,所以不需要做任何事情。使用智能指针而不是原始指针,或标准容器/ std::string
而不是您自己的hackery。更一般地说,寻找或制作遵循RAII原则的课程,以确保他们正确地清理自己。
只需在母版构造函数中将它们初始化为
nullptr
并在析构函数中尝试删除之前检查它们
FWIW,没有必要在delete
之前检查它们delete
nullptr
是一个(安全)无操作。换句话说,你添加的任何支票都是多余的,当指针不是nullptr
时可能会浪费时间。
答案 1 :(得分:2)
母亲的东西应该由母亲的构造者初始化,而不是女儿的。将所有必需的初始化参数作为构造函数参数传递给Mother的构造函数,而不是(假设您正在执行)使用子构造函数中的赋值语句。
对母亲进行编码,以便母亲可以自行构建和销毁,而不依赖任何派生类的活动。
Daughter1 daughter();
声明一个函数,没有构造函数被调用。
答案 2 :(得分:1)
另一种可能的解决方案是使用静态方法创建子对象(如here)而不是真正的构造函数。在这种情况下,你可以使构造函数非常轻量级和非抛出,只需将所有复杂的逻辑放入这些静态方法中。