kir*_*kun 10 c++ design-patterns transactional
假设我有两个函数DoTaskA和DoTaskB-both能够抛出TaskException相应的"回滚"函数UndoTaskA和UndoTaskB.什么是最好的模式,以便成功或两者都失败?
我现在最好的是
bool is_task_a_done = false,
is_task_b_done = false;
try {
DoTaskA();
is_task_a_done = true;
DoTaskB();
is_task_b_done = true;
} catch (TaskException &e) {
// Before rethrowing, undo any partial work.
if (is_task_b_done) {
UndoTaskB();
}
if (is_task_a_done) {
UndoTaskA();
}
throw;
}
Run Code Online (Sandbox Code Playgroud)
我知道这is_task_b_done是不必要的,但是如果我们稍后添加第三个或第四个任务,则可能显示代码对称性.
由于辅助布尔变量,不喜欢这段代码.也许新的C++ 11中有一些我不知道的东西,可以更好地编写代码吗?
Use*_*ess 13
一个小的RAII提交/回滚范围保护可能如下所示:
#include <utility>
#include <functional>
class CommitOrRollback
{
bool committed;
std::function<void()> rollback;
public:
CommitOrRollback(std::function<void()> &&fail_handler)
: committed(false),
rollback(std::move(fail_handler))
{
}
void commit() noexcept { committed = true; }
~CommitOrRollback()
{
if (!committed)
rollback();
}
};
Run Code Online (Sandbox Code Playgroud)
因此,我们假设在事务成功后我们将始终创建保护对象,并且commit只有在所有事务都成功后才调用.
void complicated_task_a();
void complicated_task_b();
void rollback_a();
void rollback_b();
int main()
{
try {
complicated_task_a();
// if this ^ throws, assume there is nothing to roll back
// ie, complicated_task_a is internally exception safe
CommitOrRollback taskA(rollback_a);
complicated_task_b();
// if this ^ throws however, taskA will be destroyed and the
// destructor will invoke rollback_a
CommitOrRollback taskB(rollback_b);
// now we're done with everything that could throw, commit all
taskA.commit();
taskB.commit();
// when taskA and taskB go out of scope now, they won't roll back
return 0;
} catch(...) {
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
PS.正如Anon Mail所说,最好将所有这些taskX对象推送到容器中,如果你有很多,给容器提供相同的语义(在容器上调用commit以让它提交每个拥有的guard对象).
PPS.原则上,您可以std::uncaught_exception在RAII dtor中使用而不是显式提交.我更喜欢在这里明确提交,因为我认为它更清晰,并且如果您提前退出范围return FAILURE_CODE而不是异常,也可以正常工作.
在C++中很难实现事务一致性.在Dr Dobb的期刊中使用ScopeGuard模式描述了一种很好的方法.该方法的优点在于它在正常情况和异常情况下都需要清理.它利用了以下事实:确保对象析构函数调用任何作用域出口,而异常情况只是另一个作用域出口.