メモリコピーの方法

[戻る]
ごう 2012/12/12(水) 01:11:03
下記変数について、bの内容をaにコピーしたいと思っています。

DummyT   a;       
DummyT   b = {0, 1, 2};

memcpy( (void*)&a, (void*)&b, sizeof(b) );  ・・・(1)

a = b;  ・・・(2)

個人的には、aもbも同じ変数の型を持つのでサイズはまったく同じだと思います。
(1)の方法の何が問題か理解できませんでした。
(2)の方法を使うようにしたほうがいいのでようか?
(1)の方法で考えられる問題点について、ご教示ください。

YuO [E-Mail] 2012/12/12(水) 02:01:34
DummyTがPODならよいのですが,そうでないならそもそも(1)と(2)では動作が異なります。
というよりも,(1)はDummyTの作者が想定していない使い方になります。
このため,DummyTがPODである,またはこれが「純粋なCの話である」という条件が付かない
限り,(1)は「使ってはいけない」方法になります。

POD/純粋なCでも,(1)を使う必要が無い,というのもあります。
(1)のmemcpyのために<string.h>をインクルードしなくても(2)で済むのですから。

bun 2012/12/12(水) 10:42:02
PODの話をもう少し詳しくしてみます。

(1)の方法はDummyTがC言語の構造体であるなら、問題の無いコードです。
ちなみに、void* へのキャストは暗黙のキャストが認められていますので、
  memcpy( &a, &b, sizeof(b) );
でも全く問題ありません。

同様に、PODでも問題ありません。
PODは「Plain old data structure」の略で、C言語の構造体と同等の機能しか
用いていないクラスのことです。
ではC言語の構造体以上のクラスとは何か?というと、具体例の一つが仮想関数
を含むクラスです。

仮想関数を含むクラスでは、実体(オブジェクト)を宣言すると、メンバ変数の
格納領域以外にvirtualテーブルと呼ばれる領域が確保されます。
virtualテーブルには単純にコピーするだけではまずい情報が含まれるため、
コピーすると仮想関数の仕組みが破壊されます。

また、DummyTがメンバとしてポインタ変数を持っている場合を考えましょう。
この場合、ポインタの先の領域もコピーしたいのなら、別途ポインタの先の領
域をmemcpy()した上で、コピー先の領域にポインタを更新しないといけないの
は分かるかと思います。

しかし、もし、DummyTがクラスであり、operator=()の実装を含んでいたのなら
そんな面倒なことはしなくていいのです。
(2)の方法で全てが全自動で行われるのです。

まぁ、そんなこんなで、
私自身、C++でPODのmemcpy()初期化を否定する立場ではありませんが、
PODとC++クラスの違いを完全認識した上で使うべきだと考えています。
違いが分からないで使っていると、近い将来、手痛いしっぺ返しが来ます。

古いスレッドには追加発言できません。