如何在异常时不从构造函数调用 base class 析构函数?
How to not call base class destructor from constructor on exception?
我有一些 classes Daughter1
和 Daughter2
继承自 Mother
:
class Mother
{
public:
Mother(); // Empty constructor.
virtual ~Mother(); // Delete common daughter's stuff.
protected:
// Common stuff of each daughter.
};
每个女儿的共同点class删除方法都是一样的,妈妈做主。但是,他们的初始化是不一样的,所以他们在各自女儿的构造函数中:
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
在母构造函数中并在尝试在析构函数中删除之前检查它们,但它只适用于指针和我正在寻找一个全球解决方案。
您不应该在 Mother
析构函数中删除未初始化的指针 - 只需将指针更改为智能指针,例如std::unique_ptr
他们只会在需要时 delete
自己。
更一般地,~Mother
仅在Mother
基class完成构建时被调用,然后每个成员变量应该处于任何析构函数可以安全地[=32]的状态=].对于像 double
和 int
这样的类型,没有什么可以破坏的,所以不需要做任何事情。使用智能指针而不是原始指针,或使用标准容器 / std::string
而不是您自己的 hackery。更一般地说,寻找或制作遵循 RAII 原则的 classes 以确保它们正确地自我清理。
simply initialize them to nullptr
in the mother constructor and check them before trying a deletion in the destructor
FWIW,没有必要在 delete
之前检查它们...nullptr
的 delete
是(安全的)空操作。换句话说,您添加的任何检查都是多余的,并且当指针不是 nullptr
.
时可能会浪费时间
另一种可能的解决方案是使用静态方法来创建 Daughter 对象(如 here)而不是真正的构造函数。在这种情况下,您可以使构造函数非常轻量级和非抛出,只需将所有复杂的逻辑放入这些静态方法中即可。
妈妈的东西应该由妈妈的构造函数初始化,而不是女儿的。将任何必需的初始化参数作为构造函数参数传递给 Mother 的构造函数,而不是(我假设你正在这样做)在 Daughter 构造函数中使用赋值语句。
对母体进行编码,以便母体可以自行正确构造和销毁,而无需依赖任何派生的 class 的 activity。
Daughter1 daughter();
声明了一个函数,没有调用构造函数。
我有一些 classes Daughter1
和 Daughter2
继承自 Mother
:
class Mother
{
public:
Mother(); // Empty constructor.
virtual ~Mother(); // Delete common daughter's stuff.
protected:
// Common stuff of each daughter.
};
每个女儿的共同点class删除方法都是一样的,妈妈做主。但是,他们的初始化是不一样的,所以他们在各自女儿的构造函数中:
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
在母构造函数中并在尝试在析构函数中删除之前检查它们,但它只适用于指针和我正在寻找一个全球解决方案。
您不应该在 Mother
析构函数中删除未初始化的指针 - 只需将指针更改为智能指针,例如std::unique_ptr
他们只会在需要时 delete
自己。
更一般地,~Mother
仅在Mother
基class完成构建时被调用,然后每个成员变量应该处于任何析构函数可以安全地[=32]的状态=].对于像 double
和 int
这样的类型,没有什么可以破坏的,所以不需要做任何事情。使用智能指针而不是原始指针,或使用标准容器 / std::string
而不是您自己的 hackery。更一般地说,寻找或制作遵循 RAII 原则的 classes 以确保它们正确地自我清理。
simply initialize them to
nullptr
in the mother constructor and check them before trying a deletion in the destructor
FWIW,没有必要在 delete
之前检查它们...nullptr
的 delete
是(安全的)空操作。换句话说,您添加的任何检查都是多余的,并且当指针不是 nullptr
.
另一种可能的解决方案是使用静态方法来创建 Daughter 对象(如 here)而不是真正的构造函数。在这种情况下,您可以使构造函数非常轻量级和非抛出,只需将所有复杂的逻辑放入这些静态方法中即可。
妈妈的东西应该由妈妈的构造函数初始化,而不是女儿的。将任何必需的初始化参数作为构造函数参数传递给 Mother 的构造函数,而不是(我假设你正在这样做)在 Daughter 构造函数中使用赋值语句。
对母体进行编码,以便母体可以自行正确构造和销毁,而无需依赖任何派生的 class 的 activity。
Daughter1 daughter();
声明了一个函数,没有调用构造函数。