5

我有一个包含字符数组的结构,没有任何其他成员函数。我正在这些结构的两个实例之间进行赋值操作。如果我没记错的话,它是在做浅拷贝。在这种情况下,浅拷贝安全吗?

I've tried this in C++ and it worked but I would just like to confirm if this behavior is safe.

4

2 回答 2

10

如果通过“浅拷贝”,您的意思是在分配struct包含数组的 a 之后,该数组将指向原始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

一般来说, given struct T d1, d2;,d2 = d1;等价于memcpy(&d2, &d1, sizeof d2);,但如果结构有填充,则可能会或可能不会被复制。

编辑:在 C 中,您不能分配给数组。鉴于:

int data[10] = { 0 };
int data_copy[10];

data_copy = data;

是非法的。因此,正如我上面所说,如果您在 a 中有一个数组struct,则分配给该结构必须在数组中按元素复制数据。在这种情况下,您不会得到浅拷贝:将术语“浅拷贝”应用于这种情况是没有任何意义的。

于 2010-02-11T02:00:56.487 回答
2

分配结构是按成员分配的,对于数组,这意味着分配每个项目。(这对于“多维”数组是递归完成的,它们实际上只是数组的数组。)

你是对的,它做了一个浅拷贝,即使在数组上也是如此。(我假设你没有重载 op= 相对于 C++;如果你重载它,你可以做任何你想做的事情。)

请记住,浅拷贝意味着复制某物的值,而深拷贝意味着复制某物指向或引用的值。数组的值是其中的每一项。

当您有一个执行间接的类型(例如指针)时,浅层和深层之间的区别最有意义。我发现我的回答是看待这个问题的最有用的方法,但您也可以说“浅”与“深”甚至不适用于其他类型,它们只是“复制”。

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 回答