2012-12-06 22 views
3

考慮其中函數foo(MyClass的* MC)被認爲保留MC的拷貝到內部數據結構的情況下的功能時,解決可能的內存泄漏,並確保該對象將被刪除當不再使用時。傳遞一個目的是拋出

void foo(MyClass* mc) // acquires ownership of mc; may throw 
{ 
    // code that may throw 
    bar(mc); // acquires mc; may also throw 
} 

問題出現時,這個函數執行的代碼可能拋出(例如,內存溢出除外)。如果在將指針保存到數據結構之前引發異常,那麼在函數展開之前顯然應該釋放該對象,因爲調用者沒有更多的責任(調用者甚至不知道指針是否實際上保存在數據結構與否)。

人們可以使用RAII與範圍警衛處理這個問題,但似乎很笨拙,併產生一些開銷(它在獲取指針的每一個函數來完成)。

會怎麼需要做到這一點每一個動態分配的對象被收購的時候,或者是有一個更合適的方法來做到這一點?

template <class T> 
struct VerifyAcq { 
    T* ptr; 
    bool done; 
    VerifyAcq(T* ptr):ptr(ptr) { done = false; } 
    ~VerifyAcq() { 
    if (!done) delete ptr; 
    } 
}; 

void foo(MyClass* mc) // acquires mc; may throw 
{ 
    VerifyAcq<MyClass> va(mc); 
    // code that may throw 
    bar(mc); // acquires mc; may throw; must implement the same mechanism! 
    va.done = true; 
} 
// Note: there might be no public way of "undoing" what bar has done (no rollbak) 
// and even if there was, what if it could also throw?... 

異常不能被調用者才能刪除指針,因爲拋出異常之前,該功能可能已經成功加入的指針數據結構,並在釋放對象將使數據結構抓不健全的(晃來晃去的指針)。

+0

「併產生一些開銷」替代方法是不產生「開銷」並泄漏,不是?當你付出的代價是實現目標所需的成本時,沒有「開銷」。問題:你是否控制這些功能,即,你能修復它們的接口嗎? –

+0

另一種方法是用一個全捕捉的catch塊做一個函數級try塊...這是沒有太大的替代,恕我直言 – StoryTeller

回答

4

當我開始閱讀的代碼,我停在了這一點:

void foo(MyClass* mc) // acquires ownership of mc; may throw 

註釋是沒有記錄的所有權收購的最佳途徑。最好的方法是使用類型系統。

void foo(std::unique_ptr<MyClass> mc) // no comment required 

修復接口也最終解決了這個問題。

(如果你沒有的unique_ptr在你的標準庫,也有像例如替代品,Howard Hinnant's emulation in C++03)。

+0

不錯,我忘了智能指針可以處理這種情況。 我假設'酒吧'會有相同的原型,並會被調用類似: 'bar(std :: unique_ptr (mc.release)); //?' –

1

提到RAII時你有正確的想法。

在你所提到的情況下,您表明,當bar功能不知何故未能存儲指針的缺失應該只發生。像boost::shared_ptr共享指針都非常好,認爲:

​​

只要有至少一個共享指針活躍的資源(指針),也不會被刪除。只要最後一個共享指針被銷燬或重置,資源就會被刪除。

例如:如果bar函數存儲共享指針,則在foo函數結束時不會發生刪除。或者,如果bar函數未能存儲共享指針,則foo結束時會發生刪除(假設沒有其他共享指針對資源是活動的)。

相關問題