当构造函数抛出异常时,RAII是如何工作的
How does RAII work when a constructor throws an exception?
我正在学习C++中的RAII习惯用法,以及如何使用智能指针。
在我的阅读中,我发现了两件事,对我来说,似乎是相互矛盾的。
引用自http://www.hackcraft.net/raii/:
如果已经创建了一个具有RAII语义的成员对象,并且在构造函数完成之前发生了异常,那么它的析构函数将作为堆栈展开的一部分被调用。因此,控制多个资源的对象可以保护它们的清理,即使它不是完全通过使用成员RAII对象构建的。
但引用自http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10:
如果构造函数抛出异常,则对象的析构函数不会运行。如果您的对象已经做了一些需要撤消的事情(例如分配一些内存、打开文件或锁定信号量),那么对象内部的数据成员必须记住这些"需要撤消的东西"。
然后,第二个链接源建议使用智能指针来处理构造函数中已经分配的内容的问题。
那么,在这些场景中实际会发生什么呢?
你误解了第一句话。这并不难,因为它令人困惑。
如果已经创建了一个具有RAII语义的成员对象,并且在构造函数完成之前发生了异常,那么它的析构函数将作为堆栈展开的一部分被调用。
它就是这么说的。以下是的含义:
如果已经创建了具有RAII语义的成员对象,并且在外部对象的构造函数完成之前在外部对象中发生异常,则成员对象的析构函数将作为堆栈展开的一部分被调用。
看到区别了吗?其思想是成员对象完成了它的构造函数,但拥有的类型没有。它在其构造函数(或在该构造函数之后初始化的另一个成员的构造函数)中的某个位置抛出。这将导致调用其所有成员的析构函数(即所有完成构造的成员),但不是自己的析构因子。
这里有一个例子:
class SomeType
{
InnerType val;
public:
SomeType() : val(...)
{
throw Exception;
}
};
创建SomeType
实例时,它将调用InnerType::InnerType
。只要不抛出,它就会进入SomeType
的构造函数。当抛出时,它将导致val
被销毁,从而调用InnerType::~InnerType
。
这里没有矛盾;只是在不同的语境中使用了一些令人困惑的术语。
如果对象的构造函数抛出异常,则会发生以下情况(假设异常被捕获):
- 构造函数中的所有局部变量都调用了它们的析构函数,从而释放它们获取的所有资源(如果有的话)
- 构造函数抛出异常的对象的所有直接子对象都将调用其析构函数,从而释放它们获取的资源(如果有的话)
- 构造函数抛出的对象的所有基类都将调用其析构函数(因为它们是在派生类构造函数运行之前完全构造的)
- 将进行来自呼叫者等的进一步清理
因此,由智能指针或其他RAII对象管理的任何资源(这些对象是被销毁对象的数据成员)都确实会被清理,但在对象的销毁器中进行清理的专用代码不会启动。
希望这能有所帮助!
这两个语句并不矛盾,但第一个语句使用了一些不幸的语言。当一些对象的构造抛出时,它的解构器不会被调用,但该对象所拥有的所有对象都会被其各自的解构器解构。
因此,使用RAII和智能指针,对象的任何指针成员的析构函数都将独立于所属对象的析构因子而被调用。原始指针不能释放它们所指向的内存,必须手动删除。如果所属对象的构造函数抛出原始指针,则不会释放。智能指针不可能发生这种情况。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?