自明な複素数クラスの C++ でのこれら 2 つの初期化メソッドを比較します。
complx one(1,3);
complx two = complx(3,4);
2 番目のケースでは、コンストラクターの後に代入が続くか、コピーが続くか、またはコンストラクターのみを取得しますか?
2 種類の初期化を区別することは可能ですか?
自明な複素数クラスの C++ でのこれら 2 つの初期化メソッドを比較します。
complx one(1,3);
complx two = complx(3,4);
2 番目のケースでは、コンストラクターの後に代入が続くか、コピーが続くか、またはコンストラクターのみを取得しますか?
2 種類の初期化を区別することは可能ですか?
complx two = complx(3,4);
これはコピー初期化です。このイニシャライザの特定のセマンティクスは、次のルールでカバーされています。
初期化が直接初期化である場合、またはソース型の cv 修飾されていないバージョンが [...] 宛先のクラスと同じクラスであるコピー初期化である場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され (13.3.1.3)、オーバーロード解決 (13.3) によって最適なコンストラクターが選択されます。そのように選択されたコンストラクターは、引数として初期化式または式リストを使用して、オブジェクトを初期化するために呼び出されます。[...]
つまり、コピー元の型がコピー先の型と同じであるコピー初期化は、直接初期化のように動作します。したがって、宣言は次のようになります。
complx two(complx(3,4));
これは一時complx
オブジェクトを構築し、コピー/移動コンストラクターを使用して を構築しtwo
ます。
ただし、このコピー/移動は省略される場合があります。
参照 (12.2) にバインドされていない一時クラス オブジェクトが同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合、一時オブジェクトをターゲットに直接構築することにより、コピー/移動操作を省略できます。省略されたコピー/移動の
ただし、コピー コンストラクターは、呼び出されているかのようにアクセスできる必要があります。
2 つの初期化を区別できますか? コピー/移動が有効であると仮定すると、確実ではありません。コンパイラがコピーの初期化でコピーを省略した場合、またはコピーが適切に動作し、余分な副作用がない場合、両方ともまったく同じように動作します。コピーを除外せず、コピーに余分な副作用がある場合は、違いに気付くでしょう。
C++ では、このように移動コンストラクターまたはコピー コンストラクターを実装することで、2 種類の初期化を区別できます。
struct complx
{
complx(complx && aOther){} // <- move constructor (C++11)
complx(const complx & aOther){} // <- copy constructor (C++03)
complx(float a, float b) {} // <- normal constructor
};
コードの最初の行は、通常のコンストラクターを呼び出します。コードの 2 行目は右辺値を使用したコピーの初期化と呼ばれ、C++11 では移動コンストラクターを、C++03 ではコピー コンストラクターを呼び出します。C++03 では、complx(complx && aOther){}
は認識されない (無効な構文) ため、削除する必要があることに注意してください。