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

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

问题描述

我正在学习C ++中的RAII成语,以及如何使用智能指针。



在我的阅读中,我遇到了两件事,对我来说,似乎相互矛盾。



引自 http:/ /www.hackcraft.net/raii/


...如果已经创建了具有RAII语义的成员对象,在构造函数完成之前发生异常,那么它的析构函数将被调用作为堆栈展开的一部分。因此,控制多个资源的对象即使没有使用成员RAII对象完全构造,也可以对其进行清理。


但引用自 http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10


如果构造函数抛出异常,则不会运行该对象的析构函数。如果您的对象已经完成了需要撤消的内容(例如分配一些内存,打开文件或锁定信号量),则该需要撤消的内容必须由对象中的数据成员记住。


然后,第二个链接的源建议使用智能指针来处理在构造函数中已经分配的事情的问题。 p>

那么在这些情况下实际发生了什么?

解决方案

你误会了第一个报价如果已经创建了具有RAII语义的成员对象,并且在构造函数完成之前发生异常,那么这并不困难,因为它是令人困惑的。


它的析构函数将被称为堆栈展开的一部分。


这就是说。如果已经创建了具有RAII语义的成员对象,并且发生异常,则 :


外部对象的构造函数已经完成之前,外部对象中,成员对象的析构函数将作为堆栈展开的一部分被调用。


看到区别?这个想法是成员对象完成了它的构造函数,但是拥有类型没有。它在其构造函数(或另一个成员的构造函数)中的某处被初始化。这将导致所有成员的析构函数被调用(所有已完成构造的构造函数),而不是其自己的析构函数。



这是一个例子:

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

当您创建一个 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天全站免登陆