日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深拷贝与浅拷贝、空类与空数组

發布時間:2025/7/25 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深拷贝与浅拷贝、空类与空数组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、深拷貝與淺拷貝

說得簡單點,假設一個類有指針成員,如果在拷貝的時候順帶連指針指向的內存也分配了,就稱為深拷貝,如下圖(v2 從 v 拷貝而來):


如果只是分配指針本身的內存,那就是淺拷貝,如下圖:


淺拷貝造成的問題是有兩個指針指向同塊內存,delete 其中一個指針,那么剩下的指針將成為野指針。編譯器合成的默認拷貝構造函數和賦值運算符是淺拷貝的,如果只是普通成員的賦值,淺拷貝也是可以的。

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
? #ifndef?_STRING_H_
#define?_STRING_H_

class?String
{
public:
????String(char?*str?=?"");
????~String();
????String(const?String?&other);
????String?&operator=(const?String?&other);



????void?Display();

private:
????char?*AllocAndCpy(char?*str);

????char?*str_;
};

#endif?//?_STRING_H_
C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
? #include?"String.h"
//#include?<string.h>
#include?<cstring>
#include?<iostream>
using?namespace?std;

String::String(char?*str/*?=?*/)
{
????str_?=?AllocAndCpy(str);
}

String::~String()
{
????delete[]?str_;
}

String::String(const?String?&other)
{
????str_?=?AllocAndCpy(other.str_);
}

String?&String::operator?=(const?String?&other)
{
????if?(this?==?&other)
????????return?*this;

????delete[]?str_;
????str_?=?AllocAndCpy(other.str_);
????return?*this;
}

char?*String::AllocAndCpy(char?*str)
{
????int?len?=?strlen(str)?+?1;
????char?*tmp?=?new?char[len];
????memset(tmp,?0,?len);
????strcpy(tmp,?str);
????return?tmp;
}

void?String::Display()
{
????cout?<<?str_?<<?endl;
}
C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
? #include?"String.h"

int?main(void)
{
????String?s1("AAA");
????s1.Display();
????String?s2?=?s1;?????//?調用拷貝構造函數
????//?系統提供的默認拷貝構造函數實施的是淺拷貝?s2.str_?=?s1.str_

????String?s3;
????s3.Display();
????s3?=?s2;????????????//?調用等號運算符
????//?系統提供的默認等號運算符實施的是淺拷貝?s3.str_?=?s2.str_;
????//?s3.operator=(s2);
s3.Display();
????//?要讓對象是獨一無二的,我們要禁止拷貝
????//?方法是將拷貝構造函數與=運算符聲明為私有,并且不提供它們的實現
????return?0;
}

上面程序中String 類有一個char* str_ 成員,故實現了深拷貝,這樣不會造成內存被釋放兩次的錯誤,或者修改指針指向的內存會影響另一個對象的錯誤。此外,如果我們想讓對象是獨一無二的,需要禁止拷貝,只需要將拷貝構造函數和等號運算符聲明為私有,并且不提供它們的實現。

注意:在編寫派生類的賦值函數時,不要忘記對基類的數據成員重新賦值,可以通過調用基類的賦值函數來實現,比如在

Derived& Derived::operator=(const Derived& other) { } 中調用Base::operator=(other);

注:盡量不要把 string 類型變量當作結構體成員,因為有些函數對整個結構體進行拷貝時默認就是 memcpy,即對于 string 變量來說只拷貝了指針,這可能會造成一些莫名其妙的bug,比如指針地址被重用而導致指針指向的內容可能被覆蓋重寫。--踩過的坑


二、空類與空數組

空類默認產生的成員:

class Empty {};
Empty(); // 默認構造函數 Empty( const Empty& ); // 默認拷貝構造函數 ~Empty(); // 默認析構函數 Empty& operator=( const Empty& ); ?// 默認賦值運算符 Empty* operator&(); ? ? ? ? ? ? ? // 取址運算符 const Empty* operator&() const; ? ?// 取址運算符 const

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
? #include?<iostream>
using?namespace?std;

class?Empty
{
public:
????Empty?*operator&()
????{
????????cout?<<?"AAAA"?<<?endl;
????????return?this;
????}

????const?Empty?*operator&()?const
????{
????????cout?<<?"BBBB"?<<?endl;
????????return?this;
????}
};

int?main(void)
{
????Empty?e;
????Empty?*p?=?&e;??????//?等價于e.operator&();

????const?Empty?e2;
????const?Empty?*p2?=?&e2;

????cout?<<?sizeof(Empty)?<<?endl;

????return?0;
}


單步調試一下,可以看到分別調用了兩個取地址運算符函數,而且空類的大小為1個字節。

體會一下下面的程序結果:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
? #include<iostream>
using?namespace?std;
int?main()
{
????int?a[0];
????class?B?{};
????struct?C
????{
????????int??m;
????????int??n;
????????char?buffer[];
????};
????class?D
????{
????????int??s[0];
????};

????cout?<<?"sizeof(a)="?<<?sizeof(a)?<<?endl;?//0
????cout?<<?"B{}="?<<?sizeof(B)?<<?endl;?//1
????cout?<<?"C="?<<?sizeof(C)?<<?endl;?//8
????cout?<<?"D="?<<?sizeof(D)?<<?endl;?//0

????return?0;
}


參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規范

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的深拷贝与浅拷贝、空类与空数组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。