我想写的是
void foo()
{
int a = 5;
ExecuteOnUnwind eou(bind(&cleanupFunc, a));
}
这样在函数返回或抛出异常时调用cleanupFunc(a)
。是否有一些设施可供我使用?我无法找到合适的谷歌短语,但似乎有可能出现这种情况。如果没有,我会在下面迅速制定解决方案。奇怪的是,它似乎不能在发布模式下工作,但是在vc10的调试中工作 - 我如何调整实现以使其在两者上都能保持一致,而不会有额外的临时调用风险?
编辑:修复涉及使用shared_ptr;也减轻了对临时破坏的担忧。新代码在下面
template <typename T>
struct ExecuteOnUnwindHelper
{
ExecuteOnUnwindHelper(const T & _functor) : mFunctor(_functor)
{
}
~ExecuteOnUnwindHelper()
{
mFunctor();
}
const T & mFunctor;
};
template <typename T>
boost::shared_ptr<ExecuteOnUnwindHelper<T>> ExecuteOnUnwind(const T & _functor)
{
return boost::shared_ptr<ExecuteOnUnwindHelper<T>>(new ExecuteOnUnwindHelper<T>(_functor));
}
void cleanupFunc(int a)
{
wcout << L"cleanup" << endl;
}
void foo()
{
int a = 5;
auto eou = ExecuteOnUnwind(boost::bind(&cleanupFunc, 5));
}
int main()
{
foo();
return 0;
}
答案 0 :(得分:1)
编译器必须以某种方式优化堆栈上变量的创建,因为它认为它没有被使用。也许它只是内联调用函数并跳过创建/破坏部分(我想说它是最有可能的)。它认为全局语义得以保留,但实际上它不是一个安全的优化,如你的例子所示。
我认为这是一个错误的优化,因为它显然会改变高级语义。用各种编译器进行测试会很有趣。当我有机会在家时,我会尝试VS2012。
无论如何,要强制它通过创建/销毁序列,只需使用boost::shared_ptr
,它将负责创建对象并在对象超出范围时对其进行破坏,无论是通过{ {1}}语句或通过异常抛出。
答案 1 :(得分:0)
最简单的解决方案是将所需的功能放入类型的析构函数中。在您的情况下不应该需要自动/智能指针,堆栈就足够了,可能会消除您可能遇到的编译器问题。
class ExecuteOnUnwind
{
public:
~ExecuteOnUnwind()
{
/** Do something */
}
int data;
};
void foo()
{
ExecuteOnUnwind runOnExit;
/** Functions code here */
runOnExit.data = 5;
}
如果这不起作用/不起作用,那么你可以在受影响的代码(即析构函数)周围禁用优化。:
#pragma optimize( "", off )
...
#pragma optimize( "", on )