簡體   English   中英

如何在堆棧展開時調用函數?

[英]How can I call a function on stack unwind?

我想寫的是這樣的

void foo()
{
    int a = 5;
    ExecuteOnUnwind eou(bind(&cleanupFunc, a));
}

這樣,當函數返回或引發異常時,將調用cleanupFunc(a) 是否已經有一些設施可以為我做到這一點? 我無法找到適合Google的短語,但似乎可能有某種方法可以做到這一點。 如果沒有,我很快在下面提出一個解決方案。 奇怪的是,它似乎無法在發布模式下工作,但可以在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;
}

編譯器必須以某種方式優化堆棧上變量的創建,因為它認為未使用該變量。 也許它只是內聯函數調用並跳過創建/銷毀部分(我想這是最有可能的)。 它認為保留了全局語義,但是實際上如您的示例所示,這不是安全的優化。

我認為這是一個錯誤的優化,因為它顯然會改變高級語義,使用各種編譯器進行測試將很有趣。 當我有機會在家時,我將嘗試使用VS2012。

無論如何,要強制其執行創建/銷毀序列,只需使用boost::shared_ptr ,它將負責創建對象並在對象超出范圍時對其進行銷毀,無論是通過return語句還是通過異常拋出。

最簡單的解決方案是將所需的功能放入類型的析構函數中。 在這種情況下,不需要自動/智能指針,並且堆棧就足夠了,並且可以消除您可能遇到的編譯器問題。

class ExecuteOnUnwind
{
public:
~ExecuteOnUnwind()
{
/** Do something */
}

int data;

};

void foo()
{
  ExecuteOnUnwind runOnExit;

/** Functions code here */
runOnExit.data = 5;

}

如果這不起作用,那么您可以禁用受影響代碼(即析構函數)周圍的優化。

#pragma optimize( "", off )
...
#pragma optimize( "", on )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM