2

私は PIMPL イディオムを使用しています。具体的には、この投稿で提供されているテンプレートを使用しています。以下の一連のクラスを VS2015 Update 3 でコンパイルすると、コンパイル エラーが発生します。

エラー C2027 未定義の型 'C::C_impl' の使用 (ソース ファイル src\A.cpp のコンパイル)

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

警告 C4150 不完全な型 'C::C_impl' へのポインターの削除。デストラクタが呼び出されていません (ソース ファイル src\A.cpp のコンパイル)

コメントを外すことでこれを解決できます。これによりC::~C()、何かが~C()自動生成を妨げていると思われますが、何がわかりません。このリファレンスによると、次のいずれかが true の場合、型 T のデストラクタは暗黙的に削除済みとして定義されます。

  1. T には、破棄できない非静的データ メンバーがあります (デストラクタが削除されているか、アクセスできません)。
  2. T には、破棄できない直接または仮想基底クラスがあります (削除された、またはアクセスできないデストラクタがあります)
  3. T は共用体であり、非自明なデストラクタを持つバリアント メンバを持っています。
  4. 暗黙的に宣言されたデストラクタは仮想 (基本クラスに仮想デストラクタがあるため) であり、割り当て解除関数 (演算子 delete() は、あいまいな、削除された、またはアクセスできない関数の呼び出しになります。

項目 #2、3、および 4 は明らかに には適用されません。また、 (の唯一のメンバー) がデストラクタを明示的に定義しているCため、#1 が適用されるとは思いません。pimpl<>C

誰かが何が起こっているのか説明してもらえますか?

ああ

#pragma once
#include <Pimpl.h>

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

Bh

#pragma once
#include "C.h"

class B
{
private:
    C m_C;
};

チャンネル

#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.h

#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(); }

上記のコードに関する注意事項:

  • 私は自分のライブラリの消費者に公開Aし、内部に保持しようとしています。CB
  • ここには B.cpp はありません。空になります。
4

2 に答える 2