6

次のコードは、適切にコンパイルされる有効なコードであり、型名であり、変数の名前であると仮定しTますx

構文 1:

T a(x);

構文 2:

T a = x;

これら 2 つの式の正確なセマンティクスは異なりますか? もしそうなら、どのような状況で?

これらの 2 つの式が異なるセマンティクスを持っている場合、標準のどの部分がこれについて話しているかについても非常に興味があります。

また、T がスカラー型の名前 (別名、、、、など) である特殊なケースがある場合、T がintスカラーlongdoubleと非スカラー型の違いは何ですか?

4

5 に答える 5

3

はい。x の型が でないT場合、2 番目の例は に展開されT a = T(x)ます。これには、公開されている必要がT(T const&)あります。最初の例は、コピー コンストラクターを呼び出しません。

アクセシビリティがチェックされた後、コピーを削除できます (Tony が指摘したように)。ただし、アクセシビリティを確認するに削除することはできません。

于 2011-02-21T10:00:41.370 に答える
2

8.5.14から(強調鉱山):

選択された関数は、初期化子式を引数として呼び出されます。関数がコンストラクターの場合、呼び出しは宛先タイプの一時的なものを初期化します。次に、呼び出しの結果(コンストラクターの場合は一時的なもの)を使用して、上記の規則に従って、コピー初期化の宛先であるオブジェクトを直接初期化します。場合によっては、実装は、初期化されるオブジェクトに直接中間結果を構築することにより、この直接初期化に固有のコピーを排除することが許可されます。class.temporary、class.copyを参照してください。

したがって、それらが同等であるかどうかは、実装に任されています。

8.5.11も関連していますが、違いがある可能性があることを確認する場合に限ります。

-11-初期化の形式(括弧または=を使用)は一般的に重要ではありませんが、初期化されるエンティティがクラスタイプである場合は重要です。下記参照。括弧で囲まれた初期化子は、初期化されるエンティティがクラス型である場合にのみ、式のリストにすることができます。

于 2011-02-21T09:53:00.983 に答える
2

T a(x)直接初期化であり、T a = xコピー初期化です。

標準から:

8.5.11 初期化の形式 (括弧または = を使用) は一般に重要ではありませんが、初期化されるエンティティにクラス型がある場合は重要です。下記参照。括弧で囲まれた初期化子は、初期化されるエンティティにクラス型がある場合にのみ、式のリストにすることができます。

8.5.12 引数の受け渡し、関数の戻り、例外のスロー (15.1)、例外の処理 (15.3)、および中括弧で囲まれた初期化子リスト (8.5.1) で発生する初期化は、コピー初期化と呼ばれ、次の形式と同等です。

   T x = a;

new 式 (5.3.4)、static_cast 式 (5.2.9)、関数表記法の型変換 (5.2.3)、および基本およびメンバー初期化子 (12.6.2) で発生する初期化は直接初期化と呼ばれ、フォーム

    T x(a);

違いは、コピーの初期化では、直接初期化に使用される一時オブジェクトが作成されることです。コンパイラは、一時オブジェクトの作成を回避できます。

8.5.14 ... 呼び出しの結果 (コンストラクターの場合は一時的なもの) は、上記の規則に従って、コピー初期化の宛先であるオブジェクトを直接初期化するために使用されます。場合によっては、中間結果を初期化されるオブジェクトに直接構築することにより、この直接初期化に固有のコピーを排除する実装が許可されます。12.2、12.8を参照。

コピーの初期化では、非明示的なコンストラクターとコピー コンストラクターを使用できる必要があります。

于 2011-02-21T10:40:47.703 に答える
2

ここでの違いは、暗黙的な構築と明示的な構築の違いであり、違いがある可能性があります。

Arrayconstructor を持つ型があり、Array(size_t length)別の場所に function があると想像してくださいcount_elements(const Array& array)。これらの目的は簡単に理解でき、コードは十分に読みやすいように見えますが、それによってcount_elements(2000). これは醜いコードであるだけでなく、理由もなく 2000 要素の長さの配列をメモリに割り当てます。

さらに、暗黙的に整数にキャスト可能な他の型があり、それらに対しても count_elements() を実行できるため、効率が大幅に低下してまったく役に立たない結果が得られます。

ここでやりたいことは、明示的なコンストラクターを宣言するArray(size_t length)ことです。これにより、暗黙的な変換が無効にArray a = 2000なり、有効な構文ではなくなります。

これはほんの一例です。キーワードが何をするかを理解すると、explicit他のものを思いつくのは簡単です。

于 2011-02-21T10:01:25.417 に答える
0

C ++では、これを書くと:

class A {
  public:
  A() { ... }
};

コードが何を使用するかに応じて、コンパイラは実際にこれを生成します。

class A {
  public:
  A() { ... }
  ~A() { ... }
  A(const A& other) {...}
  A& operator=(const A& other) { ... }
};

これで、さまざまなコンストラクターのさまざまなセマンティクスを確認できます。

A a1; // default constructor
A a2(a1); // copy constructor
a2 = a1; // copy assignment operator

コピーコンストラクターは、基本的にすべての非静的データをコピーします。これらは、結果のコードが合法で正気である場合にのみ生成されます。コンパイラが、コピー方法がわからないクラス内の型を(通常の代入規則に従って)検出した場合、コピーコンストラクタは生成されません。つまり、T型がコンストラクターをサポートしていない場合、またはクラスのパブリックフィールドの1つがconstまたは参照型である場合、たとえば、ジェネレーターはそれらを作成せず、コードはビルドされません。テンプレートはビルド時に展開されるため、結果のコードがビルド可能でない場合、失敗します。そして時々それは大声でそして非常に不可解に失敗します。

クラスでコンストラクタ(またはデストラクタ)を定義すると、ジェネレータはデフォルトのコンストラクタを生成しません。これは、デフォルトで生成されたコンストラクターをオーバーライドできることを意味します。それらをプライベートにする(デフォルトではパブリックにする)、オーバーライドして何もしないようにする(メモリを節約し、副作用を回避するのに役立つ)などができます。

于 2011-02-21T10:10:00.907 に答える