2017-04-13 64 views
2

我讀這個答案霍華德Hinnant(Is std::unique_ptr<T> required to know the full definition of T?),然後這個答案(How is a template instantiated?),我只是在想。如果你有像這樣模板實例化和pimpl成語與unique_ptr

class Something { 
    Something(); 
    ~Something(); 
    class Impl; 
    std::unique_ptr<Impl> impl; 
}; 

unique_ptr類時編譯將在此時被實例化一個類(因爲我可以從上面的其他答案做出來)。那麼爲什麼以後沒有定義類Impl呢?實例化是否需要Impl的析構函數存在?

注意以下是努力澄清我在上面提出的問題。

我在想這個問題,當編譯器檢查類Something的定義時。它會看到嵌套類Impl的聲明,然後它將看到unique_ptr<Impl>的聲明,並在那一點上。它將用Impl實例化模板unique_ptr。並且該實例化的代碼將包含對Impl的析構函數的調用。因爲在這一點上,我們的代碼包含對不完整類的析構函數的調用,上面的代碼如何安全?

回答

1

The accepted answer to the first question包含需要完整定義Impl的用例表。

在你的情況下,編譯器隱式生成下面的成員函數:

  • 複製構造
  • 移動構造
  • 拷貝賦值運算符
  • 移動賦值運算符。

所有這些都需要Impl的完整定義。

如果您明確聲明這些函數並在Impl的完整定義可用的情況下定義它們,那麼您將可以。

更新

將看到嵌套類Impl的聲明,然後將看到unique_ptr<Impl>的聲明,在這一點上。它將用Impl實例化模板unique_ptr

這只是在一定程度上是正確的。當時並不是所有的成員函數unique_ptr都會被實例化。

並且該實例化的代碼將包含對Impl的析構函數的調用。

不正確。只有在需要時,編譯器纔會生成代碼(或實例化)std::unique_ptr<Impl>的析構函數。那個地方是Something的破壞者。

Something的破壞者將需要破壞者std::unique_ptr<Impl>
破壞者std::unique_ptr<Impl>需要Impl的完整定義。

換句話說,Impl的完整定義必須對Something的析構函數可見。

PS

更多關於模板實例可以在Template instantiation details of GCC and MS compilers找到。

+0

成員函數爲哪個類?我還看到了第一個問題的答案,但仍然不明白,完整的'unique_ptr'類將在代碼中的指定類型(指向impl的指針的聲明)中實例化,並且該實例化將是調用'Impl'的析構函數的代碼,但這個代碼還不可見。那麼代碼是如何編譯的? – Curious

+0

@Curious,在鏈接的答案中,「P」是「shared_ptr」或「unique_ptr」。在你的情況下,隱式生成的拷貝構造函數將調用'unique_ptr '的拷貝構造函數。將該邏輯擴展到其他編譯器生成的類的成員函數。 –

+0

我不認爲我正在傳達我的想法,我會嘗試澄清在 – Curious

0

如果寫嘗試編譯上面的代碼,有所創造的一個對象,它會給出一個錯誤信息:

Semantic issue: 
memory:2523:27: Invalid application of 'sizeof' to an incomplete type 
'Something::Impl' 

總之代碼是不可編譯的,也沒有在考慮有關安全點這個案例。