从构造函数中的 catch 块调用析构函数是否安全?

Is calling destructor from a catch block in constructor safe?

在我的构造函数中,如果其中的任何代码抛出,我必须销毁所有剩余的资源。我想避免编写重复的代码,所以我只调用 catch 块中的析构函数,然后释放已创建的任何资源。这样安全吗?

我知道如果构造函数抛出,则不会调用析构函数,所以我尝试在 msvc 中编译一些代码,似乎没有任何问题,但我不确定这是否只是运气。

Object::Object(){
    try{
        // Initialize multiple resources here.
    }catch(...){
        this->~Object(); // Is this safe?
        throw;
    }
}

Object::~Object(){
    // release multiple resources, if initialized.
}

首先,invoking a member function here is fine

Member functions, including virtual functions ([class.virtual]), can be called during construction or destruction ([class.base.init]).

(您的构造函数已开始执行。)

但是 this 具体来说是关于析构函数的:

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([basic.life]). [ Example: If the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. — end example ]

因此,虽然我们知道您的析构函数不会被隐式调用 "again",但问题是随后的重新抛出是否会导致对象在某种意义上被 "again" 破坏由这段话描述。

此时我实际上放弃了标准语,我想知道这是否有点不明确。我的观点是,这本身可能足以避免这种善意的模式,而只是将您的清理放在一个很好的私有成员函数中,以便在您的 catch 块和您的析构函数之间共享。

尽管析构函数看起来像普通方法,而且显式析构语法看起来像是对该方法的调用,但它实际上并不只是调用该方法。在其他特定于实现的事情中,它还调用 base 类 和数据成员的析构函数。从构造函数中抛出异常也会导致调用所有这些析构函数。因此,~Object() 后跟 throw 将调用它们两次,可能会带来灾难性的后果。

按照评论中有人的建议,将清理代码移至普通方法即可。

构造临时对象的函数调用语法以及 new/deleteoperator new/operator delete 也存在类似的语法问题。 None 他们只是调用了具有相同名称的函数,即使看起来它们应该如此。