まず、マッツ・ピーターソンの答えは、その根拠に言及しているため、受け入れられたものよりも優れていると言えます。
第二に、補足として、もう少し詳しく説明したいと思います。
暗黙的に宣言された (またはデフォルト化された) move ctor の動作
c++draftから:
非共用体クラス X の暗黙的に定義されたコピー/移動コンストラクターは、その基底とメンバーのメンバーごとのコピー/移動を実行します。
コンパイラがムーブ ctor を暗黙的に宣言するときの条件
cppreferenceから:
クラスにユーザー定義の移動コンストラクターが提供されていない場合、次のすべてが当てはまります。
- ユーザー宣言のコピー コンストラクターがない
- ユーザー宣言のコピー代入演算子はありません
- ユーザー宣言の移動代入演算子はありません
- ユーザーが宣言したデストラクタはありません
次に、コンパイラはムーブ コンストラクターをそのクラスの非明示的なインライン パブリック メンバーとして宣言し、署名を付けますT::T(T&&)
。
dtor(および他の多くの)が暗黙的に宣言された移動ctorを防止するのはなぜですか?
上記の条件を見ると、ユーザー宣言されたデストラクタが暗黙的に宣言されたムーブ ctor を防止するだけでなく、ユーザー宣言されたコピー コンストラクター、ユーザー宣言されたコピー代入演算子、およびユーザー宣言されたムーブ代入演算子はすべて同じ防止効果を持ちます。
Mats Petersson が指摘したように、論理的根拠は次のとおりです。
移動操作でメンバーごとの移動以外の何かを行う必要があるとコンパイラが判断した場合、その必要がないと想定するのは安全ではありません。
ユーザーが宣言したデストラクタがある場合、つまりクリーンアップ作業が必要な場合は、おそらく移動元のオブジェクトでそれを実行する必要があります。
ユーザーが宣言した move 代入演算子がある場合、それもリソースを「移動」しているため、move ctor で同じことを行う必要があります。
ユーザー宣言のコピー コンストラクターまたはコピー代入演算子がある場合、これは最も興味深いケースです。move セマンティクスにより、パフォーマンスの最適化を実現しながら値のセマンティクスを維持できること、および move ctor が提供されていない場合、move はコピーに「フォールバック」することがわかっています。ある意味では、移動は「最適化されたコピー」と見なすことができます。したがって、コピー操作で何かを行う必要がある場合は、移動操作でも同様の作業が必要になる可能性があります。
上記の条件では、メンバーごとの移動以外の何かを実行する必要がある可能性があるため、コンパイラはそれが必要ないと想定せず、移動 ctor を暗黙的に宣言しません。