【问题标题】:Is shallow copy sufficient for structures with char[]?对于具有 char[] 的结构,浅拷贝是否足够?
【发布时间】:2011-01-15 13:11:13
【问题描述】:

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

我已经在 C++ 中尝试过这个并且它有效,但我想确认这种行为是否安全。

【问题讨论】:

    标签: c++ c struct shallow-copy


    【解决方案1】:

    如果通过“浅拷贝”,您的意思是在分配包含数组的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(&amp;d2, &amp;d1, sizeof d2);,但如果结构有填充,则可能会或可能不会被复制。

    编辑:在 C 中,你 can't assign to arrays。给定:

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

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

    【讨论】:

    • 是的,我理解指针的情况,但我不确定数组。
    • @jasonline:查看我的编辑。您不能在 C 中分配给数组,因此如果您的结构有数组(并且没有指针),则无法获得浅拷贝。
    • @Alok:正在输入我的答案。当然,您不能分配给数组是对的,但这不是重点。完成的是浅拷贝而不是深拷贝,即使在数组上也是如此。
    • @Roger:好的,谢谢你的解释。我认为这是一个术语问题。我同意你的观点:如果结构的数组成员包含指针,那么指针值当然会被复制。我认为 OP 的意思是如果分配给结构的数组成员“指向”原始“受让人”数组数据,而答案是“不,它不能。 "
    • @Roger:鉴于 OP 在struct 中使用char 数组,我认为我们可以确定,通过“浅拷贝”,他的意思是新的struct' s 数据将指向旧的struct 的数据。
    【解决方案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 是浅层复制的(与其他所有成员一样)。如果这些指针“拥有”它们指向的内存,那么它可能不安全。 (您问题中的“安全”含糊不清,实际上取决于您的期望和处理方式。)

    对于一个有趣的转折点,可以考虑 boost::shared_ptr 和 C++ 中的其他智能指针。即使可以进行深层复制,它们也可以进行浅层复制,这仍然是安全的。

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-07
      相关资源
      最近更新 更多