C++ では、クラスに参照データ メンバーがある場合、既定の代入演算子はコンパイラによって合成されません。なんで?
2 に答える
C ++では、クラスに参照データメンバーがある場合、デフォルトの代入演算子はコンパイラによって合成されません。なんで?
コピー割り当てが行うべきことは、次のように定義されています。
C++03標準12.8/13:
各サブオブジェクトは、そのタイプに適した方法で割り当てられます。
サブオブジェクトがクラスタイプの場合、クラスのコピー代入演算子が使用されます(明示的な修飾による場合と同様に、つまり、より派生したクラスで可能な仮想オーバーライド関数を無視します)。
サブオブジェクトが配列の場合、各要素は要素タイプに適した方法で割り当てられます。
サブオブジェクトがスカラー型の場合、組み込みの代入演算子が使用されます。
要するに、それは、各メンバーが適切な方法
で割り当てられるべきであり、それが問題を提起することを意味し
ます。クラスでの参照メンバーの割り当ての振る舞いはどうあるべきですか?
参照について次のことを考慮してください。
- 参照は本質的に割り当て不可能であり、初期化されたのと同じ参照を参照し続けます[参照1]。
- 参照に割り当てることによって
#1
、参照が再割り当てされないため、直感的でない動作である参照の値が変更されます。
ここで強制されるデフォルトの正しい動作はありませんが、状況に応じた動作です。したがって、C ++標準では、クラスの設計者がこの動作を決定するのに最適な位置にいることが義務付けられているため、クラスには参照データメンバーがあります。
この決定は次のように指定されています:
C++03標準12.8/12:
暗黙的に宣言されたコピー代入演算子は、そのクラス型のオブジェクトにそのクラス型の値またはそのクラス型から派生したクラス型の値が割り当てられたときに暗黙的に定義されます。コピー代入演算子が暗黙的に定義されているクラスが次の場合、プログラムは正しく形成されません
。.......
—参照型の非静的データメンバー、または
......。
[参照1]
C++03標準8.5.3/2:
初期化後に別のオブジェクトを参照するように参照を変更することはできません。参照の初期化は、参照への割り当てとは非常に異なる方法で処理されることに注意してください。引数の受け渡し(5.2.2)と関数値の戻り(6.6.3)は初期化です。
メンバー専用フォーラムでのディスカッションを見ました。答えはほとんどのプログラマーにはよく知られていないため、答えを投稿してここで共有したいと思います。
C++ 標準ドラフト N3337 §12.8.23 から:
クラス X のデフォルトのコピー/移動代入演算子は、X が次の場合に削除済みとして定義されます。
- 自明でない対応する代入演算子を持つバリアント メンバーであり、X が共用体のようなクラスである、または
- const 非クラス型 (またはその配列) の非静的データ メンバー、または
- 参照型の非静的データ メンバー、または
- オーバーロードの解決 (13.3) が M の対応する代入演算子に適用されるため、コピー/移動できないクラス型 M (またはその配列) の非静的データ メンバー。デフォルトの代入演算子、または
- オーバーロードの解決 (13.3) が B の対応する代入演算子に適用されるため、コピー/移動できない直接または仮想基本クラス B
- 移動代入演算子の場合、移動代入演算子を持たず自明にコピーできない型を持つ非静的データ メンバーまたは直接基底クラス、または直接または間接の仮想基底クラス。