【发布时间】:2020-07-20 18:14:10
【问题描述】:
在编写异常安全代码时,所有私有成员函数都应该至少保证基本的异常安全吗?在这种情况下,最佳/最佳做法是什么?替代品?
例如,假设我有一个类Foo 和public 函数成员DoSomething,它调用private 函数成员DoSomeOfIt。 DoSomeOfIt 可能由于某些我无法影响的功能而失败,并且当它发生时,它可能会使 Foo 对象处于部分修改状态,这违反了 Foo 的不变量。所以我可以将DoSomeOfIt 包装在try-catch 块中,并在catch 块中调用另一个private 函数成员UndoThat 来撤消DoSomeOfIt 所做的事情。单独来说,DoSomeOfIt 和 UndoThat 可能不是异常安全的,但 DoSomething 是。那会是异常安全代码吗? (本案有强保证)
class Foo {
public:
// I provide strong exception safety guarantee
void DoSomething() {
try {
DoSomeOfIt();
} catch (const std::exception& e) {
UndoThat();
throw;
}
}
private:
// I provide no exception safety guarantee.
DoSomeOfIt() {
// may throw and violate class invariants.
}
// I provide no exception safety guarantee.
UndoThat() {
// undoes everything most recent call of
// DoSomeOfIt did.
}
};
当然,我可以简单地将DoSomeOfIt 和UndoThat 的代码包含在DoSomething 中,但这可能会导致代码膨胀和函数体过长,而分解函数会使任务模块化,并可能使代码更具可读性(?)
免责声明: 我知道这可能是基于意见的。我不确定这是否会成为一篇糟糕的帖子,但我会很感激任何意见或经验,这会导致问题,或者是常见的做法等。
【问题讨论】:
-
基于意见 - 这是实施的细节;用户
Foo只关心它的公共(和受保护)接口。只要公共合同(包括例外保证)得到履行,私有实现就可以做它喜欢的任何事情。 -
每当我用 C++ 编写
catch时,我都会想知道 RAII 是否会更好。通常,(并非总是),我发现 RAII 更好。由于您暗示UndoThat()可以抛出异常,这可能是RAII 不是最佳答案的情况,但我想我会为后续读者发表评论。void DoSomething() {StateSave saveState; DoSomeOfIt(); saveState.setSucceeded();}
标签: c++ private-members private-methods exception-safety