5

他のメンバー関数を持たない文字配列を含む構造体があります。これらの構造体の2つのインスタンス間で代入演算を行っています。私が間違えなければ、それは浅いコピーをしている。この場合、浅いコピーは安全ですか?

これをC++で試しましたが、機能しましたが、この動作が安全かどうかを確認したいと思います。

4

2 に答える 2

10

「浅いコピー」とは、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、構造体に割り当てるには、配列内の要素ごとにデータをコピーする必要があります。この場合、浅いコピーは取得されません。このような場合に「浅いコピー」という用語を適用しても意味がありません。

于 2010-02-11T02:00:56.487 に答える
2

構造体を割り当てると、メンバーごとに割り当てられます。配列の場合、これは各項目を割り当てることを意味します。(これは、実際には単なる配列の配列である「多次元」配列に対して再帰的に実行されます。)

アレイ上でも、浅いコピーを実行するのは正しいです。(私はあなたが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の状況です。

papは浅くコピーされることに注意してください(他のすべてのメンバーと同様)。それらのポインタが指すメモリを「所有」している場合、それは安全ではない可能性があります。(あなたの質問の「安全」は曖昧であり、実際にはあなたが何を期待し、どのように物事を処理するかに依存します。)

興味深い工夫として、C++のboost::shared_ptrやその他のスマートポインターを検討してください。深いコピーが可能であっても、それらは浅くコピーすることができ、これは依然として安全である可能性があります。

于 2010-02-11T02:27:59.630 に答える