从构造函数中的 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
/delete
和 operator new
/operator delete
也存在类似的语法问题。 None 他们只是调用了具有相同名称的函数,即使看起来它们应该如此。
在我的构造函数中,如果其中的任何代码抛出,我必须销毁所有剩余的资源。我想避免编写重复的代码,所以我只调用 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
/delete
和 operator new
/operator delete
也存在类似的语法问题。 None 他们只是调用了具有相同名称的函数,即使看起来它们应该如此。