c/c++/c++11 淺拷貝和深拷貝

2.jpg

目錄

1 c++拷貝

1.1 拷貝構(gòu)造函數(shù)

1.2 淺拷貝

1.3 深拷貝

2 c語(yǔ)言拷貝

2.1 淺拷貝

2.2 深拷貝

3 c++11 深拷貝

正文

1 c++拷貝

1.1 拷貝構(gòu)造函
c++通過(guò)拷貝構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)象拷貝.所以先介紹一下拷貝構(gòu)造函數(shù).
實(shí)例:

class CA
{
 public:
  CA(int b,char* cstr)
  {    ...  }
  CA(const CA& C)
  {
   a=C.a;
   str=C.str
  }
 private:
  int a;
  char *str;
};

CA A(100,"123")//構(gòu)造函數(shù)賦值
CExample B=A;//拷貝構(gòu)造函數(shù)賦值
CExample C(A);//拷貝構(gòu)造函數(shù)賦值
CExample D; D=A;//賦值構(gòu)造函數(shù)賦值
g_fun(A);//傳值拷貝調(diào)用對(duì)象構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)實(shí)現(xiàn)分析:
調(diào)用g_Fun()時(shí),會(huì)產(chǎn)生以下幾個(gè)重要步驟:
(1).函數(shù)調(diào)用傳值拷貝,會(huì)先會(huì)產(chǎn)生一個(gè)臨時(shí)變量,就叫 C 吧。
(2).然后調(diào)用拷貝構(gòu)造函數(shù)把A的值給C.整個(gè)這兩個(gè)步驟有點(diǎn)像:CA C(A);
(3).等g_Fun()執(zhí)行完后, 析構(gòu)掉 C 對(duì)象。C對(duì)象完成了在g_Fun()函數(shù)內(nèi)部的工作.
1.2 淺拷貝
淺拷貝只拷貝基本數(shù)據(jù)類型(非指針變量).
對(duì)于指針變量,對(duì)象B的指針變量會(huì)指向對(duì)象A的指針變量?jī)?nèi)存,不會(huì)拷貝.
類缺省拷貝構(gòu)造函數(shù)是淺拷貝.上例中的拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)就是淺拷貝.
淺拷貝的問(wèn)題是如果對(duì)象中變量帶有指針,則會(huì)發(fā)生錯(cuò)誤.因?yàn)閮蓚€(gè)指針指向同一個(gè)內(nèi)存,一個(gè)對(duì)象修改,另一個(gè)對(duì)象的值也被更改了.
當(dāng)在析構(gòu)的時(shí)候,會(huì)發(fā)生兩次free同一個(gè)內(nèi)存,造成錯(cuò)誤.

下面的link介紹了淺拷貝和c的簡(jiǎn)單神拷貝.c++深拷貝參見1.3節(jié),c的高級(jí)深拷貝參見2.2節(jié)。
參見https://blog.csdn.net/cyy_0802/article/details/80374812
1.3 c++深拷貝
在拷貝構(gòu)造函數(shù)中分配內(nèi)存,將入?yún)?duì)象的指針變量指向的內(nèi)存,全部拷貝一份就是深拷貝。
實(shí)例分析

class CA
{
 public:
  CA(int b,char* cstr)
  {
   a=b;
   str=new char[b];
   strcpy(str,cstr);
  }
  CA(const CA& C)
  {
   a=C.a;
   str=new char[a]; //深拷貝
   if(str!=0)
    strcpy(str,C.str);
  }
 private:
  int a;
  char *str;
};

CA A(10,"Hello!");//構(gòu)造函數(shù)初始化對(duì)象。
CA B=A; //拷貝構(gòu)造函數(shù).
上例將str的內(nèi)容拷貝一份,實(shí)現(xiàn)了深拷貝.
擴(kuò)展問(wèn)題,如果類中變量不是char* str,而是另一個(gè)對(duì)象的指針會(huì)怎么樣?

class CB
{
 public:
    CB(int b,CA* q)
  {  ...} 
  CB(const CB& C)
  {  
        aa=C.b; 
        p(C.q); //嵌套調(diào)用CA的拷貝構(gòu)造函數(shù)做深拷貝.CA的拷貝構(gòu)造函數(shù)見上例
    }
    private:
    int aa;
  CA *p;
};
CA A(10,"Hello!");//先要?jiǎng)?chuàng)建出類中組合的對(duì)象,然后才能拷貝.
CB AA(11,A);//初始化AA
CB BB=AA;//拷貝構(gòu)造函數(shù)

2 c語(yǔ)言拷貝

2.1 淺拷貝
和上面的c++淺拷貝一樣. 兩個(gè)指針指向同一個(gè)內(nèi)存.

char *p,*q="abc";
p=q;

2.2 深拷貝
(1) 如果struct中沒(méi)有指針變量
直接拷貝內(nèi)存即可.

struct CC *p,*q;
q=(struct CC*)malloc(sizeof(struct CC));
q->a=100;
...//struct 賦值
memcpy(p,q);

(2) 如果struct中帶有指針變量
需要自己實(shí)現(xiàn)拷貝函數(shù),將每個(gè)item拷貝一份.(實(shí)現(xiàn)類似c++的拷貝構(gòu)造函數(shù))

typedef struct Node//結(jié)構(gòu)體
{
int size;
char *data;
}S_Node;
void CopyNode(S_Node *node3, S_Node node1)//CopyNode 函數(shù)實(shí)現(xiàn)結(jié)構(gòu)體變量的深拷貝
{
node3->size = node1.size;
node3->data = (char *)malloc(node3->size + 1);//申請(qǐng)空間
assert(node3->data != NULL);
strcpy(node3->data, node1.data);
}
S_Node node1;
node1.data = (char *)malloc(sizeof(char)*100);
S_Node node3;
CopyNode(&node3, node1);

擴(kuò)展情況:如果將char *data換成struct S_NodeA *nodeA會(huì)怎么樣呢?

void CopyStruct(S_Node *node3, S_Node node1)//CopyNode 函數(shù)實(shí)現(xiàn)結(jié)構(gòu)體變量的深拷貝
{
    node3->size = node1.size;
    node3->data = (char *)malloc(node3->size + 1);//申請(qǐng)空間
    CopyNode(&nodeA,node1);
}

CopyStruct將非struct的item拷貝一份。nodeA需要嵌套拷貝.調(diào)用拷貝S_Node的函數(shù)CopyNode完成拷貝.
總結(jié):淺拷貝就是指針賦值,不分配內(nèi)存,兩個(gè)指針指向一個(gè)內(nèi)存. 深拷貝就是拷貝指針指向的內(nèi)存.如果有嵌套對(duì)象的話,嵌套拷貝.

3 C++11 深拷貝

c++11 使用移動(dòng)構(gòu)造函數(shù)實(shí)現(xiàn)深拷貝
移動(dòng)構(gòu)造函數(shù)的原理是,指針A和B同時(shí)指向一塊內(nèi)存,然后將原來(lái)的A指針置NULL. 這樣避免了兩個(gè)指針指向同一個(gè)內(nèi)存,也避免了內(nèi)存拷貝.

本文如對(duì)您有幫助,請(qǐng)隨手點(diǎn)個(gè)贊,謝謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容