当构造函数抛出异常时,RAII如何工作? [英] How does RAII work when a constructor throws an exception?

查看:472
本文介绍了当构造函数抛出异常时,RAII如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习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


I am learning about the RAII idiom in C++, and how to use smart pointers.

In my reading, I have come across two things that, to me, seem to contradict each other.

Quoted from http://www.hackcraft.net/raii/:

...if a member object with RAII semantics has been created and an exception happens before the constructor has completed then its destructor will be called as part of the stack unwinding. Hence an object which controls multiple resources can guarnatee their cleanup even if it isn’t fully constructed by using member RAII objects.

But quoted from http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10:

If a constructor throws an exception, the object's destructor is not run. If your object has already done something that needs to be undone (such as allocating some memory, opening a file, or locking a semaphore), this "stuff that needs to be undone" must be remembered by a data member inside the object.

And then the second linked source recommends using smart pointers to deal with the issue of things that were already allocated in the constructor.

So what actually happens in these scenarios?

解决方案

You're misunderstanding the first quote. That's not hard, since it's confusing.

if a member object with RAII semantics has been created and an exception happens before the constructor has completed then its destructor will be called as part of the stack unwinding.

That's what it says. Here's what it meant:

if a member object with RAII semantics has been created and an exception happens in the outer object before the outer object's constructor has completed then the member object's destructor will be called as part of the stack unwinding.

See the difference? The idea is that the member object completed its constructor, but the owning type didn't. It threw somewhere in its constructor (or a constructor of another member that is initialized after that one). This will cause the destructor of all of its members to be called (all of the ones that completed construction, that is), but not its own destructor.

Here's an example:

class SomeType
{
  InnerType val;
public:
  SomeType() : val(...)
  {
    throw Exception;
  }
};

When you create a SomeType instance, it will call InnerType::InnerType. As long as that doesn't throw, it will then enter SomeType's constructor. When that throws, it will cause val to be destroyed, thus calling InnerType::~InnerType.

这篇关于当构造函数抛出异常时,RAII如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆