他のメンバー関数を持たない文字配列を含む構造体があります。これらの構造体の2つのインスタンス間で代入演算を行っています。私が間違えなければ、それは浅いコピーをしている。この場合、浅いコピーは安全ですか?
これをC++で試しましたが、機能しましたが、この動作が安全かどうかを確認したいと思います。
他のメンバー関数を持たない文字配列を含む構造体があります。これらの構造体の2つのインスタンス間で代入演算を行っています。私が間違えなければ、それは浅いコピーをしている。この場合、浅いコピーは安全ですか?
これをC++で試しましたが、機能しましたが、この動作が安全かどうかを確認したいと思います。
「浅いコピー」とは、struct
含む配列を割り当てた後、配列が元struct
のデータを指すことを意味します。つまり、それはできません。配列の各要素を新しいにコピーする必要がありstruct
ます。構造体にポインタがある場合、「浅いコピー」が画像に表示されます。そうでない場合は、浅いコピーを行うことはできません。
含む配列をある値に割り当てるstruct
と、浅いコピーを実行できません。これは、配列への割り当てを意味するため、違法です。したがって、取得する唯一のコピーはディープコピーです。
検討:
#include <stdio.h>
struct data {
char message[6];
};
int main(void)
{
struct data d1 = { "Hello" };
struct data d2 = d1; /* struct assignment, (almost) equivalent to
memcpy(&d2, &d1, sizeof d2) */
/* Note that it's illegal to say d2.message = d1.message */
d2.message[0] = 'h';
printf("%s\n", d1.message);
printf("%s\n", d2.message);
return 0;
}
上記は印刷されます:
Hello
hello
一方、struct
ポインタがあった場合、struct
代入はポインタのみをコピーします。これは「浅いコピー」です。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char *message;
};
int main(void)
{
struct data d1, d2;
char *str = malloc(6);
if (str == NULL) {
return 1;
}
strcpy(str, "Hello");
d1.message = str;
d2 = d1;
d2.message[0] = 'h';
printf("%s\n", d1.message);
printf("%s\n", d2.message);
free(str);
return 0;
}
上記は印刷されます:
hello
hello
一般に、与えられたstruct T d1, d2;
、はとd2 = d1;
同等memcpy(&d2, &d1, sizeof d2);
ですが、構造体にパディングがある場合、それはコピーされる場合とされない場合があります。
編集:Cでは、配列に割り当てることはできません。与えられた:
int data[10] = { 0 };
int data_copy[10];
data_copy = data;
違法です。したがって、上で述べたように、に配列がある場合struct
、構造体に割り当てるには、配列内の要素ごとにデータをコピーする必要があります。この場合、浅いコピーは取得されません。このような場合に「浅いコピー」という用語を適用しても意味がありません。
構造体を割り当てると、メンバーごとに割り当てられます。配列の場合、これは各項目を割り当てることを意味します。(これは、実際には単なる配列の配列である「多次元」配列に対して再帰的に実行されます。)
アレイ上でも、浅いコピーを実行するのは正しいです。(私はあなたがC++に関してop=をオーバーロードしていないと仮定しています;それをオーバーロードすればあなたはあなたが望むことを何でもすることができます。)
浅いコピーは何かの値をコピーすることを意味し、深いコピーは何かが指しているまたは参照している値をコピーすることを意味することを忘れないでください。配列の値は、その中の各項目です。
浅いものと深いものの違いは、ポインターなどの間接参照を行う型がある場合に最も意味があります。私の答えはこの問題を調べるのに最も役立つ方法だと思いますが、「浅い」と「深い」は他のタイプにも当てはまらず、単に「コピー」されていると言うこともできます。
struct S {
int n;
int* p;
int a[2];
int* ap[2];
int xy[2][2];
};
void f() {
S c, d;
c = d;
// equivalent to:
c.n = d.n;
c.p = d.p;
c.a[0] = d.a[0]; // S::a is similar to your situation, only using
c.a[1] = d.a[1]; // int instead of char.
c.ap[0] = d.ap[0];
c.ap[1] = d.ap[1];
c.xy[0][0] = d.xy[0][0];
c.xy[0][1] = d.xy[0][1];
c.xy[1][0] = d.xy[1][0];
c.xy[1][1] = d.xy[1][1];
}
上記のintを使用しても、セマンティクスは変更されません。char配列でも同じように機能し、各charをコピーします。これは私のコードのS::aの状況です。
pとapは浅くコピーされることに注意してください(他のすべてのメンバーと同様)。それらのポインタが指すメモリを「所有」している場合、それは安全ではない可能性があります。(あなたの質問の「安全」は曖昧であり、実際にはあなたが何を期待し、どのように物事を処理するかに依存します。)
興味深い工夫として、C++のboost::shared_ptrやその他のスマートポインターを検討してください。深いコピーが可能であっても、それらは浅くコピーすることができ、これは依然として安全である可能性があります。