【发布时间】:2021-04-13 19:19:47
【问题描述】:
我有一个功能,我希望有强大的异常保证:
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 操作。
我还希望任何解决方案都是零 - 快乐路径上的开销;我真的需要尽可能快的快乐之路。
【问题讨论】:
-
强异常保证并不总是与零开销兼容。在这种情况下,如果您确实需要强异常保证,请复制原始向量,修改副本和
swap,一旦风险部分完成。这是最强大的解决方案。 -
当您有一个打算重新抛出的
catch块时,您可以使用throw;重新抛出异常。这也是从通用catch(...)块重新抛出的唯一方法。 -
@Cory Kramer 是的,这是一个错误,代码已编辑。但是之前的 push_back 可能已经成功了(例如 vector3 push_back 失败但之前的 2 有效)所以我仍然需要做一些 pop_back 。
-
您的恢复状态到底是什么?向量处于其原始状态?如果是这样,为什么不先
reserve,如果失败了,那么你知道并且可以抛出,否则对push_back的调用应该是好的。 -
你真的有四种不同的异常类型吗?
标签: c++ raii exception-safety