2013-08-06 4 views
7

例えば、それは私を困惑:C++のデフォルトの割り当て動作は何ですか?

Aのフィールド bufを通じて
struct A { 
// some fileds... 
    char buf[SIZE]; 
}; 

A a; 
a = a; 

、それはデフォルトの割り当て操作はYに、オブジェクトXを割り当てることmemcpyのようなものを呼び出すことのように、おそらく見えますので、どのような自体にオブジェクトを割り当てる場合上にa = a;のような明示的な割り当て操作は定義されていません。

memcpyのマニュアルページ:

DESCRIPTION 

The memcpy() function copies n bytes from memory area src to memory area dest. The memory areas must not overlap. Use memmove(3) if the memory areas do overlap. 

使用memcpy、いくつかの未定義の動作が発生することがあります。

C++オブジェクトのデフォルトの割り当て動作は何ですか?

+0

なぜmemcpyは未定義の動作を引き起こしますか? 2つの異なる配列オブジェクトは重複しません(もちろん、* 1つの*例外がありますが、ここでは関係ありません)。 –

+0

@ R.MartinhoFernandesデフォルトの代入演算の振る舞いがmemcpyの場合、 'a = a'を呼び出すため、メモリ領域は重複してはいけません –

+1

領域からコピーする場合は重複の問題があります文字列に文字を挿入し、 'memcpy(&a [index + 1]、&a [index]、len-index);'を実行します。しかし、 'memcpy(a、a、sizeof(a))'はうまくいくでしょう。 –

答えて

12

代入演算子はmemcpy(12.8/28)で定義されていません。

非組合 クラスXのために暗黙的に定義されたコピー/移動代入演算子は、サブオブジェクトのコピー/移動を割り当てmemberwise行います。 Xの直接基底クラスが最初に割り当てられ、 の宣言がbase-specifier-listにあり、次に Xの非静的データメンバーが が宣言された順番で割り当てられますクラス定義の中で。 xを関数のパラメータ とするか、または移動演算子の場合は パラメータを参照するxvalueとします。各サブオブジェクトは、その タイプに適した方法で割り当てられている:

[...]

- サブオブジェクトが配列の場合、各要素は、要素タイプに適切な 方法で、割り当てられています。

[...]

ご覧のように、各char要素が個別に割り当てられます。それは常に安全です。

char配列と同じ動作をするため、if-ifルールの下では、コンパイラはこれをmemmoveと置き換えることがあります。理論的にそのようなことが定義されていなくても、memcpyがこの同じ振る舞いになることを保証できれば、それをmemcpyに置き換えることもできます。コンパイラは理論的に未定義の動作に依存することができます。定義されていない動作が存在する理由の1つは、コンパイラがその操作に適したものを定義できるようにすることです。

実際、この場合、コンパイラはas-ifルールをさらに引き継ぐことができ、アレイではまったく何もしません。なぜなら、同様の結果になるからです。

2

デフォルトの割り当て(およびコピー)動作では、クラス全体をmemcpyにすることはできません。各メンバは、コピーコンストラクタまたは代入演算子(操作に応じて)を使用してコピーされます。これは、メンバーとそのメンバーに対して再帰的に適用されます。基本的なデータ型に達すると、単にmemcpyに似たデータのストレートコピーを実行します。したがって、基本的なデータ型の配列はmemcpyと同様にコピーされますが、クラス全体はコピーされません。クラスにstd :: stringを追加すると、配列のコピーとともにその=演算子が呼び出されます。 array of std :: stringを使用した場合、配列内の各文字列には演算子が呼び出されます。彼らはmemcpyしません。

+2

その答えは部分的に正しいが、OPが尋ねる特定のケースは含まれていない。 –

+0

memcpyが使用されないので、memcpyルールの違反はそれ以上は関連しません。しかし、私は自己割り当てについて議論していたはずです。 –

+0

実際には、デフォルトのオペレータが自己割り当てをどのように処理するかわかりません。私の勘違いは、それが明示的にではなく、そのようなことを防ぐ必要のあるメンバーに依存して、彼らのカスタム割り当て演算子で独自のチェックを行うことです。 –

0

いくつかの限定された実験では、g ++はコピーしようとするすべての試みを完全に取り除いてくれます。a = a; [明白であると仮定すれば、十分にポインタを混乱させると、最終的に同じオブジェクトをそれ自身にコピーし、未定義の動作]。

+2

UBを取得できません。要素別コ​​ピー(12.8,28)で定義され、要素ごとの自己割り当ては明確に定義されています。 –

-1

memcpyを使用すると、未定義の動作が発生することがあります。

これは、指定されたクラスがどのようにコピーされるかの実装の詳細です。 memcpy()関数とコピーコンストラクタの両方が、いくつかのマシンコードに変換されます。ただし、デフォルトの割り当てでは重複しても適切な結果が得られるとは保証されないため、メモリ内のオブジェクトは重複しないようにしてください。

C++オブジェクトのデフォルトの割り当て動作は何ですか?他の応答と同様に

行動は、それが再帰的にすべてのクラス/構造体のメンバに割り当てを呼び出すようなものです。しかし、技術的には、あなたの場合のように、メモリのブロック全体をコピーするだけで、構造がPOD(普通の古いデータ)の場合は特にそうです。

+0

これは間違っています。暗黙コピーコンストラクタは自己割り当てで正常に動作します。 (そしてそれは無関係で、例題は初期化ではなく代入に関するものです) –

+0

正確に何が間違っていますか?私は自己割り当てではなく、重なり合ったオブジェクトを指していました。重なり合うオブジェクトでは、動作は未定義です。 – Karadur

+0

コピーコンストラクタの?いいえ、そうではありません。 (どのようにオブジェクトが重複してコピーコンストラクタを呼び出すのですか?) –

関連する問題