web-dev-qa-db-ja.com

unique_ptrを使用した前方宣言?

次のコードのように、std::unique_ptrと組み合わせてクラスの前方宣言を使用すると便利です。 GCCでコンパイルして動作しますが、全体がちょっと奇妙に見えますが、これが標準的な動作(つまり、標準で必要とされる)かどうか疑問に思いますか? unique_ptrを宣言するとき、Bは完全な型ではありません。

A.hpp

#include <memory>

class B;

class A {
    std::unique_ptr<B> myptr;
    // B::~B() can't be seen from here
public:
    ~A();
};

A.cpp

#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.

A::~A() = default; // without this line, it won't compile 
// however, any destructor definiton will do.

これはデストラクタに関係していると思われる(したがって、unique_ptr<B>のデストラクタを呼び出す必要がある)は、特定のコンパイル単位(A.cpp)で定義されています。

58
Zyx 2000

明示的に合法です。ルールは、標準ライブラリでテンプレートをインスタンス化するために使用される型は完全でなければならないということです。そうでない場合は、nlessを指定します。 _unique_ptr_の場合、§20.7.1/ 5は「[...] unique_ptrのテンプレートパラメーターTは不完全な型である可能性があります」と述べています。

完全な型を必要とするポインターには特定の操作があります。特に、オブジェクトが実際に破棄される場合(少なくともデフォルトの削除機能を使用する場合)。あなたの例では、例えば、A::~A()がインラインの場合、これは問題を引き起こすかもしれません。 (デストラクタを自分で宣言しないとインラインになります。これは_std::unique_ptr_を使用する目的を部分的に無効にします。)

59
James Kanze