c++ - 如何设计具有强异常保证的函数?

标签 c++ raii exception-safety

我有一个函数,我希望它具有强大的异常保证:

class X {
   /* Fields and stuff */
   void some_function() {
       vector1.push_back(/*...*/); // May Throw
       vector2.push_back(/*...*/); // May Throw
       vector3.push_back(/*...*/); // May Throw
       vector4.push_back(/*...*/); // May Throw
   }
};
我能想到的具有强大异常保证的唯一方法如下:
class X {
   /* Fields and stuff */
   void some_function() {
       try { vector1.push_back(/*...*/);};
       catch (Vector1PushBackException) {
            throw Vector1PushBackException;
       }
       try { vector2.push_back(/*...*/);};
       catch (Vector2PushBackException) {
            vector1.pop_back();
            throw Vector2PushBackException;
       }
       try { vector3.push_back(/*...*/);};
       catch (Vector3PushBackException) {
            vector1.pop_back();
            vector2.pop_back();
            throw Vector3PushBackException;
       }
       try { vector4.push_back(/*...*/);};
       catch (Vector4PushBackException) {
            vector1.pop_back();
            vector2.pop_back();
            vector3.pop_back();
            throw Vector4PushBackException;
       }
   }
};


然而,这真的很丑陋而且容易出错!!有没有比我上面提到的更好的解决方案?我可以听到有人告诉我我需要使用 RAII,但我不知道如何使用,因为 pop_back当函数正常返回时,不得进行操作。
我也希望任何解决方案都是零 - 快乐路径上的开销;我真的需要尽可能快的快乐之路。

最佳答案

解决方法是使用scope guards .
this answer对于它们的示例实现;我不会在这里重复。使用范围守卫,您的代码将如下所示:

vector1.push_back(/*...*/);
FINALLY_ON_THROW( vector1.pop_back(); )
vector2.push_back(/*...*/);
FINALLY_ON_THROW( vector2.pop_back(); )
vector3.push_back(/*...*/);
FINALLY_ON_THROW( vector3.pop_back(); )
vector4.push_back(/*...*/);
FINALLY_ON_THROW( vector4.pop_back(); )
在这里,FINALLY_ON_THROW是一个宏(见上面的链接)。它不是立即执行它的参数,而是在您由于异常离开当前范围时执行它。如果您以正常方式离开范围,则该参数将被忽略。如果您在控制权首先到达守卫之前离开范围,它也会被忽略。
请注意,如果最后一个守卫之后(在同一范围内)没有任何东西可以抛出,则它是多余的。

关于c++ - 如何设计具有强异常保证的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67081148/

相关文章:

java - synchronized 关键字异常安全吗?

c++ - std::list 的多元素插入是强异常安全的吗?

c++ - "checking for self-assignment"有什么问题,它是什么意思?

c++ - 这个失败的测试是否将零添加到空指针未定义的行为、编译器错误或其他什么?

c# - 在 native 可执行文件中嵌入 .net 二进制文件

c++ - GUI 和 RAII : Cleenup by destructor or window close, 窗口生命周期

c++ - 这个单例类会在销毁时自动释放内存吗?

c++ - 如何从一维数组中提取子图像?

c++ - 为什么这个 C++ for 循环的执行时间有显着差异?

rust - "struct field is never used",但 RAII 需要