也许我在考虑这个问题,但请考虑以下示例:
bool some_state = false;
// ... later ...
some_state = true;
do_something();
some_state = false;
现在假设do_something()
可以投掷。我们不会将some_state
设置回false
。什么是好的是有一些自动堆栈,基于范围推送/弹出记住以前的值:
{
scoped_restore res( some_state, true ); // This sets some_state to true and remembers previous value (false)
do_something();
} // At this point, res is destroyed and sets some_state back to false (previous value)
boost有这样的东西吗?我当然可以写自己的对象,但我想确保我不是先重新发明轮子。我在MSVC上使用C ++ 03,所以不幸的是我不能使用任何花哨的新C ++ 11 :(
答案 0 :(得分:1)
Boost 确实有这样的东西。它被称为state_saver。它被隐藏在序列化库中,但是它被记录下来并且显然是官方的(即不在某些细节命名空间中)。
http://www.boost.org/doc/libs/1_56_0/libs/serialization/doc/state_saver.html
答案 1 :(得分:0)
你正在咆哮着正确的树。 Bjarne Stroustrup强烈建议使用RAII进行异常处理而不是try / catch / finally。在最新版的“C ++编程语言”(第4版)中,他完全概述了第13章“异常处理”中推荐的方法。
很难替换整个章节,所以首先,我建议只阅读本章。但是,基本思想是使用组合并让构造函数保护资源。
所以,如果你有一个A类来保护每个可能抛出的3个资源(可能是一些内存),你可以让子对象在它的构造函数(而不是A的构造函数)中保护它们。关键点在于,如果允许构造函数完成,则可以保证(通过语言)将调用析构函数。因此,在顶层构造函数中初始化子对象,如下所示:
class B{
public:
B( int n )
{
//allocate memory (may throw)
}
void *secured_memory;
~B(){
//release memory
}
}
class A{
public:
A( int n )
:b{n}, c{n}, d{n}
{
//will not complete if B, C or D throws
//but because the constructors of B and C completed
//their destructors will be invoked if D throws
}
B b;
C c;
D d;
}
想象一下C类和D类存在,它们的结构类似于B.因此,在上面的例子中,some_state将通过类似B,C或D的类来保护。
这里的另一个关键点。您应该只保护每个子对象的类中的单个资源。这样,获取资源并允许构造函数退出(从而确保调用析构函数将安全地释放资源)或抛出(因此,不获取资源)。