哪种代码被认为是异常安全的?

Aqu*_*irl 5 c++ mutex exception-handling exception pthreads

处理异常的代码称为异常安全代码?它是否正确?

从这里:https://codereview.stackexchange.com/a/9759/11619

您为互斥锁使用锁定/解锁对.这不是例外.所以我会创建一个对象,它将在构造函数中执行锁定并在析构函数中解锁,然后使用它来锁定互斥锁.这将使您的代码更加安全.

class MutexLocker
{
    pthread_mutex_t&  mutex;
    MutextLocker(pthread_mutex_t& mutex)
        : mutex(mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    ~MutexLocker()
    {
        pthread_mutex_unlock(&mutex);
    }
};
Run Code Online (Sandbox Code Playgroud)

以上显示的代码异常以哪种方式安全?我没有在那里看到任何异常处理.

或者异常安全代码是指我们可以"添加"异常处理的地方吗?因此,通过添加异常处理可以使上面显示的代码异常安全,但现在不是吗?

Mat*_* M. 7

例外安全不是关于处理异常,而是即使在存在异常的情况下也要保证关于程序的许多属性.

您通常可以谈论给定方法的异常安全级别:

  • 不保证:这种方法是不安全的例外,根本不保证.
  • 基本异常保证:如果异常没有资源泄露且涉及的类仍然可用(但是它们的状态未指定),那就是没有内存泄漏,没有文件句柄泄漏,没有互斥泄漏,所涉及的实例的不变量仍然存在验证.
  • 强烈异常保证:如果发生异常,所有状态都会逆转到开始之前的状态.这是一个像语义一样的事务.
  • NoThrow保证:这种方法不会抛出,它总是成功的.

在一般情况下,不抛出保证只适用于最简单的方法(即.size()vector例如)和强异常保证可能是昂贵的实施(能够恢复的影响或对国家的拷贝操作可能不便宜).

另一方面,基本例外保证就是:基本.没有它,安全地运行程序是不可能的,所以这是可接受的最小保证.如果泄漏资源或使类处于不可用状态,程序可能无法进一步操作.

这就是为什么每当提到例外情况时都会强调RAII.因为RAII保证资源(内存,互斥体,文件)的自动清理,无论路径执行(常规返回或异常),都是特别需要的.但是,RAII本身还不够.

相关:Herb Sutter关于异常安全和异常规范的入门.

  • 我将"无异常保证"称为"无保证",以避免与"无保证"混淆.我会说,在基本保证的情况下,对象保持"有效但未指定的状态" - 也就是说类不变量是按照你的说法维护的,但强调异常后对象的值抛出可能是*任何东西*.然后"可用"是对象用于什么的问题 - 它们可以被破坏,但除此之外它们可能不是非常有用*ful*. (2认同)

Man*_*rse 2

“异常安全”是一个相当重载的术语,但我会用它来描述可以抛出异常并仍然保持某些不变量的代码段(例如 - 没有任何变化,没有资源泄漏,所有对象都保持有效状态)。

举个例子,你的void * printHello (void* threadId)函数是正确的(因为它总是与 匹配pthread_mutex_lock (&demoMutex)pthread_mutex_unlock (&demoMutex),但是如果有人更改了中间的部分,以便它可以抛出异常(例如,通过在 上设置抛出标志std::cout),那么你的代码将然后永久锁定demoMutex,不希望它被释放。这将构成您的程序中的错误。void * printHello (void* threadId)被称为“异常不安全”,因为通过在看似不相关的部分添加异常处理,可以很容易地将错误引入到您的程序中。

使用 RAII 类来管理资源是编写异常安全代码的好方法(并且是在 C++ 中使用的资源管理风格),因为它避免了块中重复的手动清理的需要catch(...),并且它通过以下方式强制清理资源:使用类型系统。