2016-07-21 22 views
1

私はPIMPLイディオムを使用しています。具体的には、this postから提供されたテンプレートを使用しています。下のクラスのセットを考えるとVS2015アップデート3は、私はエラーがコンパイル取得していてコンパイルする:(ソースファイルSRC \ A.cppをコンパイル)未定義の型「C :: C_impl」のPIMPLイディオムを使用すると、このタイプが不完全なのはなぜですか?

エラーC2027の使用を

エラーC2338は不完全な型(ソースファイルsrc \ A.cppのコンパイル)を削除できません。

警告C4150不完全な型 'C :: C_impl'へのポインタの削除。 (コンパイルソースファイルSRC \ A.cpp)と呼ばれるデストラクタない

何私は何かが自動的に生成されることから~C()を妨げているが、私は何を理解していないと信じて私をリードされ、C::~C()のコメントを外すことによって、これを解決することができます。

  1. Tを破壊することができない非静的データメンバーを有する(デストラクタを削除またはアクセスできないた)
  2. :削除されたように、次のいずれかが真である場合 this referenceによれば、タイプTのデストラクタが暗黙的に定義されています
  3. Tには、破壊できない直接的または仮想的な基底クラスがあります(削除された、またはアクセスできないデストラクタを持っています)。
  4. Tは共用体であり、トリガーではないデストラクタを持つ変形メンバを持っています。
  5. 暗黙的に宣言さデストラクタは仮想(基底クラスが仮想デストラクタを持っているので)と、あいまいな、削除、またはアクセス不可能な関数の呼び出しで解放関数(delete演算子()の結果のルックアップです。

アイテム#2、3、および4は明らかにCには適用されません、と私はpimpl<>C年代唯一のメンバー)は、明示的にデストラクタを定義するため、#1が適用されることを信じていません。

誰かが説明していただけます何が起こっているのですか?

A.h

#pragma once 
#include <Pimpl.h> 

class A 
{ 
private: 
    struct A_impl; 
    pimpl<A_impl> m_pimpl; 
}; 

B.h

#pragma once 
#include "C.h" 

class B 
{ 
private: 
    C m_C; 
}; 

C.h

#pragma once 
#include <Pimpl.h> 

class C 
{ 
public: 
    // Needed for the PIMPL pattern 
    //~C(); 

private: 
    struct C_impl; 
    pimpl<C_impl> m_pimpl; 
}; 

A.cpp

#include <memory> 
#include "A.h" 
#include "B.h" 
#include <PimplImpl.h> 

struct A::A_impl 
{ 
    std::unique_ptr<B> m_pB; 
}; 

// Ensure all the code for the template is compiled 
template class pimpl<A::A_impl>; 

C.cpp

#include <C.h> 
#include <PimplImpl.h> 

struct C::C_impl { }; 

// Needed for the PIMPL pattern 
//C::~C() = default; 

// Ensure all the code for the template is compiled 
template class pimpl<C::C_impl>; 

は完全を期すために、後からPIMPL実装は上記で参照:

pimpl.h

#pragma once 
#include <memory> 

template<typename T> 
class pimpl 
{ 
private: 
    std::unique_ptr<T> m; 
public: 
    pimpl(); 
    template<typename ...Args> pimpl(Args&& ...); 
    ~pimpl(); 
    T* operator->(); 
    T& operator*(); 
}; 

PimplImpl。時間

#pragma once 
#include <utility> 

template<typename T> 
pimpl<T>::pimpl() : m{ new T{} } {} 

template<typename T> 
template<typename ...Args> 
pimpl<T>::pimpl(Args&& ...args) 
    : m{ new T{ std::forward<Args>(args)... } } 
{ 
} 

template<typename T> 
pimpl<T>::~pimpl() {} 

template<typename T> 
T* pimpl<T>::operator->() { return m.get(); } 

template<typename T> 
T& pimpl<T>::operator*() { return *m.get(); } 

上記のコードについての注意事項:私は私のライブラリの消費者にACを公開し、内部Bを維持しようとしている

  • ここにB.cppはありません。それはempyです。

答えて

2

デフォルトのコンパイラは使用時にCデストラクタを生成しようとしますが、C :: C_implの定義が見つからない場合は、C :: C_implの定義の後に手動でCデストラクタを定義する必要があります、それはB.cppになります)。

+0

それは意味があります、私はそれが使用の時点で生成されたことを認識していませんでした。ありがとう! –

1

std::unique_ptrは、インスタンス化時に破棄関数(つまり、デストラクタ)を知る必要があると考えています。 A.cppでそれに入手可能な情報にpimpl<C_impl>オブジェクトを削除しようとしていることを意味し、コンパイラは、使用の時点でそれを生成~C()デフォルトのデストラクタと

。もちろん、C_implはその時点でのみ宣言されているので、コンパイラはC_implオブジェクトをどのように破壊するかを知らず、エラーが発生します。

コメントを外します。~C();は、C_implの破壊方法を気にしないようにコンパイラに指示します。これは他の場所で定義されます。あなたの場合はC.cppで定義されており、C_implの定義は知られています。あなたの編集に応答して

pimpl<C_impl>のデストラクタはアクセスできないデストラクタ(C_implが使用withing A.cppの点で不完全な型である)を有する非静的データメンバを有するstd::unique_ptr<C_impl>を有しています。

関連する問題