
目錄
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)存拷貝.