2012-01-26 10 views
54

ここでは、pimplのためにunique_ptrを使用しようとしているところを単純化しています。私はクラスが本当にポインタを所有したいので、unique_ptrを選択しました - 私はpimplポインタとクラスのライフタイムを同じにします。ここでpimplにunique_ptrを使用するにはどうすればよいですか?

#ifndef HELP 
#define HELP 1 

#include <memory> 

class Help 
{ 

public: 

    Help(int ii); 
    ~Help() = default; 

private: 

    class Impl; 
    std::unique_ptr<Impl> _M_impl; 
}; 

#endif // HELP 

ソースされています:

#include "Help.h" 

class Help::Impl 
{ 
public: 
    Impl(int ii) 
    : _M_i{ii} 
    { } 

private: 

    int _M_i; 
}; 

Help::Help(int ii) 
: _M_impl{new Help::Impl{ii}} 
{ } 

は私だけで罰金ライブラリにこれらをコンパイルすることができ

とにかく、ここにヘッダがあります。私はテストプログラムでそれを使用しようとすると、しかし、私はこれはよく知られてsafety featureある

[email protected]:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp 
In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0, 
       from Help.h:4, 
       from test_help.cpp:3: 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Help::Impl]': 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:245:4: required from 'void std::unique_ptr<_Tp, _Dp>::reset(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>; std::unique_ptr<_Tp, _Dp>::pointer = Help::Impl*]' 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:169:32: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>]' 
Help.h:6:7: required from here 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:63:14: error: invalid application of 'sizeof' to incomplete type 'Help::Impl' 

を取得します。私は従うことを試みた。

私の問題は、ヘッダーにHelp :: Impl宣言を置くと、pimplの利点を取り除いているようです。クラスレイアウトはユーザーに表示されます。定義は隠されていますが、私はヘルプクラスとプライベートメンバーでそれを行うことができました。また、Implの宣言を含めて、私は別々に保つことが好きだっただろう新しいヘッダーをもたらします。

私には何が欠けていますか?人々はImpl宣言に何を入れ、どこで?私はヘルプのdtorを間違っているのですか?アー!

+2

[GotW#101:Compilation Firewalls、Part 2](http://herbsutter.com/gotw/_101/)および[この関連する質問](http://stackoverflow.com/q/8595471)/636019)。 – ildjarn

+1

これは古い質問ですが、「unique_ptr」で実装されたPImplは、(cppreference(http://en.cppreference.com/w/cpp/language/pimpl)で説明されているように)完全な正確さのために、['propagate_const'](http://en.cppreference.com/w/cpp/experimental/propagate_const)のようなものにラップしてください。 – jdehesa

+1

@jdehesaありがとう、私はいくつかのAPIの厄介さの解決策としてpropagate_constを見ていました。私は、unique_ptrがこの意味でデフォルトで壊れているかどうか、ほとんど疑問に思います。これは、propagate_constが組み込まれているか、少なくともデフォルトである必要があります。 – emsr

答えて

69

私はあなたのtest_help.cppがデフォルトで宣言した~Help()デストラクタを実際に見ていると思います。そのデストラクタでは、コンパイラはunique_ptrデストラクタも生成しようとしますが、そのためにはImpl宣言が必要です。

したがって、デストラクタ定義をHelp.cppに移動すると、この問題は解決されます。

- EDIT - あなたはすぎ、CPPファイルのデフォルトであることをデストラクタを定義することができます。

Help::~Help() = default; 
+9

さて、ヘッダーで私はちょうどヘルプ用のdtorを*宣言しました。次に、実装ファイルでHelp ::〜Help()= default; Woot !!!ありがとう。すべてが動作します! – emsr

+0

優れたもの –

+4

'unique_ptr'を含むスマートポインタは、不完全な型で動作する必要があります。 "deleter"関数は、構築時に割り当てられます。そのため、ポインタのユーザは、削除方法を知る必要がありません。これが問題を解決すれば、彼の 'unique_ptr'実装が壊れていることを暗示します。 –

1

注これをunique_ptr定義から:

のstd :: unique_ptrをpImplイディオムにおけるハンドルとしての使用を容易にするために、不完全な型Tに対して構成することができる。デフォルトのDeleterが使用されている場合、Tはデリータが呼び出されるコード内のポイントで完了する必要があります。デストラクタ、移動代入演算子、およびstd :: unique_ptrのメンバ関数のリセットが行われます。

関連する問題