2

我想写的是

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

2 回答 2

1

编译器必须以某种方式优化堆栈上变量的创建,因为它认为它没有被使用。也许它只是内联对函数的调用并跳过创建/销毁部分(我会说这是最有可能的)。它认为保留了全局语义,但实际上它不是您的示例所示的安全优化。

我认为这是一个错误的优化,因为它显然改变了高级语义。用各种编译器测试会很有趣。当我在家里有机会时,我会尝试使用 VS2012。

无论如何,要强制它通过创建/销毁序列,只需使用 a boost::shared_ptr,它会负责创建对象并在对象超出范围时销毁它,无论是通过return语句还是通过异常抛出。

于 2013-03-07T00:43:26.990 回答
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 )
于 2013-03-07T00:41:38.297 回答