5
// main_pimpl_sample.cpp
#include "pimpl_sample.hpp"

using namespace std;

int main()
{
  pimpl_sample p;

  return 0;
}

// pimpl_sample.cpp 

#include "pimpl_sample.hpp"

struct pimpl_sample::impl {
};

pimpl_sample::pimpl_sample()
  : pimpl_(new impl) {
}

// pimpl_sample::~pimpl_sample()
// cause problem if missed
// {}


// pimpl_sample.hpp

#if !defined (PIMPL_SAMPLE)
#define PIMPL_SAMPLE

#include <boost/scoped_ptr.hpp>

class pimpl_sample {
  struct impl;
  boost::scoped_ptr<impl> pimpl_;

public:
  pimpl_sample();
  //~pimpl_sample(); cause problem if missed
  void do_something();
};

#endif


~/Documents/C++/boost $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

~/Documents/C++/boost $ g++ -o main_pimpl_sample main_pimpl_sample.cpp pimpl_sample.cpp pimpl_sample.hpp
In file included from /usr/include/boost/smart_ptr/scoped_ptr.hpp:15:0,
                 from /usr/include/boost/scoped_ptr.hpp:14,
                 from pimpl_sample.hpp:6,
                 from main_pimpl_sample.cpp:2:
/usr/include/boost/checked_delete.hpp: In function ‘void boost::checked_delete(T*) [with T = pimpl_sample::impl]’:
/usr/include/boost/smart_ptr/scoped_ptr.hpp:80:9:   instantiated from ‘boost::scoped_ptr<T>::~scoped_ptr() [with T = pimpl_sample::impl]’
pimpl_sample.hpp:8:20:   instantiated from here
/usr/include/boost/checked_delete.hpp:32:58: error: invalid application of ‘sizeof’ to incomplete type ‘pimpl_sample::impl’ 
/usr/include/boost/checked_delete.hpp:32:58: error: creating array with negative size (‘-0x00000000000000001’)

上記のコンパイルエラーの解決策は、手動でデストラクタを提供することです。示された理由は次のとおりです。

デストラクタを手動で定義することを忘れないでください。その理由は、コンパイラが暗黙のデストラクタを生成するときに、型implが不完全であるため、そのデストラクタが呼び出されないためです。

質問>上記のアイデアを理解するのはまだ難しいので、ここで手動デストラクタを提供する必要がある理由について少し詳しく知りたいと思います。

ありがとうございました

4

1 に答える 1

7

TL; DR明示的なデストラクタを宣言し、それをコードモジュール(ヘッダーファイルではなく)に実装します。

デストラクタを作成しない場合、コンパイラは、このクラスのオブジェクトを破棄しようとするすべての変換ユニットに空の自動デストラクタを作成します。クラスヘッダーで空のインラインデストラクタを定義した場合、同等の動作が得られます。

これによりエラーが発生します。これは、デストラクタがすべてのクラスのフィールドのデストラクタを呼び出す役割も果たしているためです。この場合、メソッドテンプレートのインスタンス化が必要になりますboost::scoped_ptr<impl>::~scoped_ptr();。このテンプレートは、そのスコープで前方宣言されているタイプのオブジェクトを削除しようとするため、インスタンス化できませんimpl(このオブジェクトを削除する方法を知るには、完全な定義が必要です。


OTOH、ヘッダーで非インラインコンストラクターを宣言すると、そのコードはでのみ生成されpimpl_sample.cppます。ここには、の定義もimpl含まれているため、scoped_ptrのデストラクタを正常にインスタンス化できます。

他の変換ユニットは、外部メソッドとしてデストラクタを呼び出すだけpimpl_sampleなので、デストラクタを生成しscoped_ptrて自分でインスタンス化する必要はありません。

于 2011-12-23T19:18:15.620 に答える