2011-10-25 74 views
1

boost::scoped_ptr documentation包含一個被稱爲Handle/Body Idiom的技巧的例子。它是在以下的話有描述:boost :: scoped_ptr文檔不一致?

的scoped_ptr_example_test.cpp示例程序包括一個頭文件, scoped_ptr_example.hpp,其採用了scoped_ptr的<>到一個不完整的類型 到隱藏實現。

然而,在同一時間,在documentation for checked_delete中指出:

特別麻煩的情況是,當一個智能指針的析構函數,如 的boost :: scoped_ptr的::〜scoped_ptr的,被實例化爲不完整類型。 這往往會導致沉默,難以追蹤失敗。 提供的函數和類模板可用於防止這些問題,因爲它們 需要完整類型,否則會導致編譯錯誤。

scoped_ptr確實在其實施中使用checked_delete。對我來說,這兩段看起來相互矛盾。另外,我無法編譯我的代碼,試圖採用建議的伎倆有以下消息:

checked_delete.hpp:32: error: invalid application of 'sizeof' to 
incomplete type 'MyClass' 

因此,着實的scoped_ptr文檔erronous還是我只是錯過了什麼?

回答

4

它們互不矛盾。因爲scoped_ptr是一個模板,並且由於代碼中沒有顯式實例化,所以每個方法都根據需要進行實例化。這意味着類型必須在~scoped_ptr<>實例化完成之前完成,在這種情況下,該類型在保持類型完成後在.cpp文件中完成(在靠近文件結尾處尋找example::~example(){},這是~scoped_ptr<>被實例化的地方)

這其實是一個很有意思的用例爲用戶定義的析構函數,看起來完全一樣,產生將編譯器,但允許您控制其中時破壞恰好能夠與一些PIMPL模式/ 聰明的指針。如果析構函數沒有被聲明和定義,那麼析構函數會在需要時由編譯器隱式定義,並且類型將不完整,從而導致UB。

+0

實際上,析構函數和構造函數都必須是用戶定義的。如果使用編譯器生成的默認構造函數,那麼編譯器會嘗試在'main()'中實例化'scoped_ptr',其中類型不完整。 – FireAphis

+0

實際上,'shared_ptr'沒有這樣的問題,因爲它使用類型擦除來創建在構造函數中實例化的刪除對象。僅供參考,完全可以在類中使用'shared_ptr'來指定不完整​​的類型,並且只爲該類定義一個構造函數。 –

+0

@FireAphis:構造函數不需要用戶定義。 「scope_ptr」模板的實例化並不意味着「scope_ptr」的析構函數被實例化了,只有那些被使用的方法被實例化了,我不認爲它是未定義的,因此對不完整類型使用構造函數傳遞/存儲一個指針,這對於不完整的類型是很好的) - 也就是說,假設構造函數沒有動態分配類型,而不完整類型又是一個問題。 –

2

類模板的成員函數僅在使用 時實例化。唯一的地方是boost::scoped_ptr::~scoped_ptr被用於ins 的破壞者example。其定義見 scoped_ptr_example.cpp,定義後 ​​已完成。函數 boost::checked_delete被設計爲如果 類型不完整則不會編譯; boost::scoped_ptr::~scoped_ptr使用此代碼,以便 代碼不會編譯,如果您嘗試在 類型不完整的上下文中調用它。

(FWIW:在PIMPL方法使用boost::scoped_ptr是有點大材小用, 而不是非常有用,因爲你必須提供一個用戶定義的析構函數 無論如何,它確實沒有給你買多少,並增加了一個小位 複雜性。)

+0

「_impaint :: scoped_ptr'在pimpl習語中有點矯枉過正,並不是很有用_」很明顯,自我記錄和使用scoped_ptr來表示獨佔所有權的好習慣。 – curiousguy

+0

@curiousguy'scoped_ptr'在pimpl習語中確實不會給你多少錢,因爲你仍然需要實現析構函數。我可以理解關於意向文檔的論點,但是如果這個類只包含一個名爲'myImpl'的指針,或者類似於'Impl'的類型,我會說這個意圖不僅僅是清晰的;你已經超越了獨佔所有權,並明確了使用的實際模式。 –

+0

我同意你的評論。但我認爲有必要提出一致性:如果涉及獨佔所有權,則儘可能使用'scoped_ptr'。 (但是如果你不這樣做,我不介意。) – curiousguy