Is shallow copy sufficient for structures with char[]?

旧巷老猫 提交于 2019-11-30 22:00:50
Alok Singhal

If by "shallow copy", you mean that after assignment of a struct containing an array, the array would point to the original struct's data, then: it can't. Each element of the array has to be copied over to the new struct. "Shallow copy" comes into the picture if your struct has pointers. If it doesn't, you can't do a shallow copy.

When you assign a struct containing an array to some value, it cannot do a shallow copy, since that would mean assigning to an array, which is illegal. So the only copy you get is a deep copy.

Consider:

#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;
}

The above will print:

Hello
hello

If, on the other hand, your struct had a pointer, struct assignment will only copy pointers, which is "shallow copy":

#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;
}

The above will print:

hello
hello

In general, given struct T d1, d2;, d2 = d1; is equivalent to memcpy(&d2, &d1, sizeof d2);, but if the struct has padding, that may or may not be copied.

Edit: In C, you can't assign to arrays. Given:

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

data_copy = data;

is illegal. So, as I said above, if you have an array in a struct, assigning to the struct has to copy the data element-wise in the array. You don't get shallow copy in this case: it doesn't make any sense to apply the term "shallow copy" to a case like this.

Assigning structs does a member-wise assignment, and for arrays this means assigning each item. (And this is done recursively for "multiple dimension" arrays, which are really just arrays of arrays.)

You are correct that it does a shallow copy, even on arrays. (I'm assuming that you have not overloaded op= with respect to C++; if you overload it you can do anything you want.)

Remember that a shallow copy means copying the value of something, while a deep copy means copying the value to which something points or refers. The value of an array is each item in it.

The difference between shallow and deep is most meaningful when you have a type that does indirection, such as a pointer. I find my answer the most helpful way to look at this issue, but you could also say "shallow" vs "deep" doesn't even apply to other types, and they are just "copied".

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];
}

That I used int above doesn't change anything of the semantics, it works identically for char arrays, copying each char. This is the S::a situation in my code.

Note that p and ap are copied shallowly (as is every other member). If those pointers "own" the memory to which they point, then it might not be safe. ("Safe" in your question is vague, and really depends on what you expect and how you handle things.)

For an interesting twist, consider boost::shared_ptr and other smart pointers in C++. They can be copied shallowly, even though a deep copy is possible, and this can still be safe.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!