如何在堆栈中调用函数展开?

时间:2013-03-06 23:50:55

标签: c++ boost

我想写的是

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;
}

2 个答案:

答案 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 )