6

次の例で、 Foomoveコンストラクターが呼び出そうとする理由を理解するのに問題があります。~ptr

#include <utility>

template <typename T, typename Policy>
class ptr {
    T * m_t;
public:
    ptr() noexcept : m_t(0) {}
    explicit ptr(T *t) noexcept : m_t(t) {}
    ptr(const ptr &other) noexcept : m_t(Policy::clone(other.m_t)) {}
    ptr(ptr &&other) noexcept : m_t(other.m_t) { other.m_t = 0; }
    ~ptr() noexcept { Policy::delete_(m_t); }
    ptr &operator=(const ptr &other) noexcept
    { ptr copy(other); swap(copy); return *this; }
    ptr &operator=(ptr &&other) noexcept
    { std::swap(m_t,other.m_t); return *this; }

    void swap(ptr &other) noexcept { std::swap(m_t, other.m_t); }

    const T * get() const noexcept { return m_t; }
    T * get() noexcept { return m_t; }
};

class FooPolicy;
class FooPrivate;
class Foo {
    // some form of pImpl:
    typedef ptr<FooPrivate,FooPolicy> DataPtr;
    DataPtr d;
public:
    // copy semantics: out-of-line
    Foo();
    Foo(const Foo &other);
    Foo &operator=(const Foo &other);
    ~Foo();

    // move semantics: inlined
    Foo(Foo &&other) noexcept
      : d(std::move(other.d)) {} // l.35 ERR: using FooDeleter in ~ptr required from here
    Foo &operator=(Foo &&other) noexcept
    { d.swap(other.d); return *this; }
};

GCC 4.7:

foo.h: In instantiation of ‘ptr<T, Policy>::~ptr() [with T = FooPrivate; Policy = FooPolicy]’:
foo.h:34:44:   required from here
foo.h:11:14: error: incomplete type ‘FooPolicy’ used in nested name specifier

Clang 3.1-pre:

foo.h:11:14: error: incomplete type 'FooPolicy' named in nested name specifier
    ~ptr() { Policy::delete_(m_t); }
             ^~~~~~~~
foo.h:34:5: note: in instantiation of member function 'ptr<FooPrivate, FooPolicy>::~ptr' requested here
    Foo(Foo &&other) : d(std::move(other.d)) {}
    ^
foo.h:23:7: note: forward declaration of 'FooPolicy'
class FooPolicy;
      ^
foo.h:11:20: error: incomplete definition of type 'FooPolicy'
    ~ptr() { Policy::delete_(m_t); }
             ~~~~~~^~
2 errors generated.

どうしたの?copyctorsとdtorsの実行を避けるためにmoveコンストラクターを書いています。これはその実装(pimplイディオム)を隠そうとするヘッダーファイルであるためFooDeleter、完全な型を作成することはオプションではないことに注意してください。

編集:Boの回答の後、noexcept可能な限り追加しました(上記で編集)。しかし、エラーは同じです。

4

1 に答える 1

9

メンバーFooを含む新しいオブジェクトを作成します。ptr<something>コンストラクタが失敗した場合Foo、コンパイラは、部分的に構築されたの完全に構築されたメンバーのデストラクタを呼び出す必要がありFooます。

ただし、インスタンス化できない~ptr<incomplete_type>()ため、失敗します。

プライベートデストラクタでも同様のケースがあります。これにより、そのタイプのオブジェクトを作成できなくなります(友人またはメンバー関数から作成された場合を除く)。

于 2012-02-23T17:24:31.167 に答える