2010-02-11 57 views
4

我有一個包含沒有任何其他成員函數的字符數組的結構。我正在做這些結構的兩個實例之間的賦值操作。如果我沒有弄錯,它正在做淺拷貝。在這種情況下淺拷貝是否安全?對於帶有char []的結構,淺拷貝是否足夠?

我已經在C++中嘗試了這一點,它的工作原理,但我只想確認此行爲是否安全。

回答

9

如果使用「淺拷貝」,則表示在分配包含數組的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中,你can't assign to arrays。鑑於:

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

data_copy = data; 

是非法的。所以,正如我上面所說,如果你有一個struct中的數組,分配給結構必須在數組中複製數據元素。在這種情況下,您不會獲得淺拷貝:將「淺拷貝」一詞應用於這種情況沒有任何意義。

+0

是的,我理解指針的情況,但我只是不確定數組。 – jasonline 2010-02-11 02:09:02

+0

@jasonline:看我的編輯。你不能分配給C中的數組,所以如果你的結構有數組(沒有指針),你就不能得到淺拷貝。 – 2010-02-11 02:16:14

+0

@Alok:正在輸入我的答案。當然,你是無法分配給數組的,但那不是重點。即使在數組上,淺拷貝也不是深拷貝。 – 2010-02-11 02:30:05

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不會改變語義的任何東西,它的作用相同的字符數組,複製每個字符。這是我的代碼中的S ::情況。

注意pAP較淺複製(如每隔一個成員)。如果這些指針「擁有」它們指向的內存,那麼它可能不安全。 (在你的問題中「安全」是模糊的,真的取決於你的期望和你如何處理事情。)

對於一個有趣的轉折,考慮boost :: shared_ptr和C++中的其他智能指針。儘管可以進行深層複製,但它們可以被淺拷貝,並且這仍然是安全的。