2015-12-22 15 views
10

次のコードではmovable<T>を含むwrapper<T>オブジェクトが宣言されています。ここでTは不完全な型です。 movableのデストラクタは、Tの完全な知識なしにはインスタンス化できないように作られていますが、wrapperのデストラクタは前方宣言されているだけです。つまり~wrapper()の定義ポイントで~movable()がインスタンス化されていれば十分です。noexceptコンストラクタはデストラクタのインスタンス化を必要とするのはなぜですか?

#include <utility> 

template<class T> 
struct movable { 
    movable() noexcept = default; 
    ~movable() noexcept { (void) sizeof(T); } 
    movable(const movable&) noexcept = delete; 
    movable(movable &&) noexcept = default; 
}; 

template<class T> 
class wrapper { 
public: 
    movable<T> m; 
    wrapper() noexcept = default; 
    wrapper(wrapper &&) noexcept = default; 
    ~wrapper(); 
}; 

struct incomplete; 

int main() { 
    /* extern */ wrapper<incomplete> original; 
    wrapper<incomplete> copy(std::move(original)); 
} 

(Try it here)

しかし、wrapper()~movable()をインスタンス化したいと考えています。例外の場合には、メンバーの破壊が可能でなければならないが、movable()wrapper()はどちらも例外ではない。興味深いことに、移動コンストラクタは正常に動作します(例コードのextern部分のコメントを外してみてください)。

この動作の理由は何ですか?回避する方法はありますか?

+1

打ち鳴らすコンパイルが失敗します。 – interjay

+0

Hm、 "クラステンプレートの完全性がプログラムのセマンティクスに影響を与える可能性がある場合、クラステンプレートはインスタンス化されます" ...多分それは何か関係がありますか? –

+0

クラスに複数のメンバがあり、構築中に初期化のうちの1つがスローされた場合、前に完了した初期化は、それぞれのメンバのデストラクタを呼び出すことによって元に戻す必要があります。私はあなたが見るものはこれに関連していると思います。 – dyp

答えて

4

TCによって観察されるように、非委任コンストラクタにおいて

、[...]のデストラクタがクラス型の各非静的データメンバーが潜在的に起動された[...]

DR1424によると、デストラクタが親オブジェクトのコンストラクタからアクセスできない場合、実装には例外が発生する可能性はない所与のサブオブジェクトの構成に従う」。潜在的に呼び出されたデストラクタがODR-使用であるとして、あなたの問題が発生する場所である、

movable<T>のデストラクタはアクセス可能ですが、それはインスタンス化することはできません。

これは、各サブオブジェクトがアクセス可能な、必要な場合にはインスタンス化可能なデストラクタを持つかどうかを検証し、オプティマイザに残して、不要なデストラクタ呼び出しを排除することができるため、代替案は恐ろしく複雑になります。後続のサブオブジェクトが構築可能でないかどうか、およびコンストラクター本体に依存するかどうかによって、デストラクタは必要とされません。

デストラクタの潜在的な呼び出しを回避するための唯一の方法は、サブオブジェクトの寿命を自分の管理を引き継ぐ、新しい配置を用いることであろう

: `extern`のコメントを解除した場合でも

#include <new> 
// ... 
template<class T> 
class wrapper { 
public: 
    std::aligned_storage_t<sizeof(movable<T>), alignof(movable<T>)> m; 
    wrapper() noexcept { new (&m) movable<T>; }; 
    wrapper(wrapper&& rhs) noexcept { new (&m) movable<T>{reinterpret_cast<movable<T>&&>(rhs.m)}; } 
    ~wrapper(); 
}; 
関連する問題