1、new和delete的內(nèi)部實現(xiàn)
C++中如果要在堆內(nèi)存中創(chuàng)建和銷毀對象需要借助關(guān)鍵字new
和delete
來完成。比如下面的代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class CA { public : CA()m_a(0){} CA( int a):m_a(a){} virtual void foo(){ cout<<m_a<<endl;} int m_a; }; void main() { CA *p1 = new CA; CA *p2 = new CA(10); CA *p3 = new CA[20]; delete p1; delete p2; delete [] p3; } |
new
和delete
既是C++中的關(guān)鍵字也是一種特殊的運算符。
1
2
3
4
|
void * operator new ( size_t size); void * operator new []( size_t size); void operator delete ( void *p); void operator delete []( void *p); |
new
和delete
不僅承載著內(nèi)存分配的功能還承載著對象構(gòu)造函數(shù)的調(diào)用功能,因此上面的對象創(chuàng)建代碼其實在編譯時會轉(zhuǎn)化為如下的實現(xiàn):
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
|
CA *p1 = operator new ( sizeof (CA)); //分配堆內(nèi)存 CA::CA(p1); //調(diào)用構(gòu)造函數(shù) CA *p2 = operator new ( sizeof (CA)); //分配堆內(nèi)存 CA::CA(p2, 10); //調(diào)用構(gòu)造函數(shù) CA *p3 = operator new [](20 * sizeof (CA)); CA *pt = p3; for ( int i = 0; i < 20; i++) { CA::CA(pt); pt += 1; } CA::~CA(p1); operator delete (p1); CA::~CA(p2); operator delete (p2); CA *pt = p3; for ( int i = 0; i < 20; i++) { CA::~CA(pt); pt += 1; } operator delete [](p3); |
看到上面的代碼也許你會感到疑惑,怎么在編譯時怎么會在源代碼的基礎(chǔ)上插入這么多的代碼。這也是很多C程序員吐槽C++語言的原因:C++編譯器會偷偷插入很多未知的代碼或者對源代碼進行修改和處理,而這些插入和修改動作對于程序員來說是完全不可知的! 言歸正傳,我們還能從上面的代碼中看出new和delete操作其實是分別進行了2步操作:1.內(nèi)存的分配,2.構(gòu)造函數(shù)的調(diào)用;3.析構(gòu)函數(shù)的調(diào)用,4.內(nèi)存的銷毀。所以當(dāng)對象是從堆內(nèi)存分配時,構(gòu)造函數(shù)執(zhí)前內(nèi)存就已經(jīng)完成分配,同樣當(dāng)析構(gòu)函數(shù)執(zhí)行完成后內(nèi)存才會被銷毀。 這里面一個有意思的問題就是當(dāng)我們分配或者銷毀的是數(shù)組對象時,系統(tǒng)又是如何知道應(yīng)該調(diào)用多少次構(gòu)造函數(shù)以及調(diào)用多少次析構(gòu)函數(shù)的呢?答案就是在內(nèi)存分配里面。當(dāng)我們調(diào)用operator new[]來分配數(shù)組對象時,編譯器時系統(tǒng)內(nèi)部會增加4或者8字節(jié)的分配空間用來保存所分配的數(shù)組對象的數(shù)量。當(dāng)對數(shù)組對象調(diào)用構(gòu)造和析構(gòu)函數(shù)時就可以根據(jù)這個數(shù)量值來進行循環(huán)處理了。因此上面對數(shù)組對象的分配和銷毀的真實代碼其實是按如下方式處理的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// CA *p3 = new CA[20]; 這句代碼在編譯時其實會轉(zhuǎn)化為如下的代碼片段 unsigned long *p = operator new [](20 * sizeof (CA) + sizeof (unsigned long )); //64位系統(tǒng)多分配8字節(jié) *p = 20; //這里保存分配的對象的數(shù)量。 CA *p3 = (CA*)(p + 1); CA *pt = p3; for ( int i = 0; i < *p; i++) { CA::CA(pt); pt += 1; } // delete[] p3; 這句代碼在編譯時其實會轉(zhuǎn)化為如下的代碼片段 unsigned long *p = ((unsigned long *)p3) - 1; CA *pt = p3; for ( int i = 0; i < *p; i++) { CA::~CA(pt); pt += 1; } operator delete [](p); |
可見C++中為我們隱藏了多少細節(jié)啊!既然new
和delete
操作默認(rèn)是從堆中進行內(nèi)存分配,而且new
和delete
又是一個普通的運算符函數(shù),那么他內(nèi)部是如何實現(xiàn)呢?其實也很簡單。我們知道C語言中堆內(nèi)存分配和銷毀的函數(shù)是malloc/free
。因此C++中對系統(tǒng)默認(rèn)的new
和delete
運算符函數(shù)就可以按如下的方法實現(xiàn):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
void * operator new ( size_t size) { return malloc (size); } void * operator new []( size_t size) { return malloc (size); } void operator delete ( void *p) { free (p); } void operator delete []( void *p) { free (p); } |
這里需要注意的是你在代碼里面使用new關(guān)鍵字和使用operator new
操作符所產(chǎn)生的效果是不一樣的。如果你在代碼里面使用的是new關(guān)鍵字那么系統(tǒng)內(nèi)部除了會調(diào)用operator new操作符來分配內(nèi)存還會調(diào)用構(gòu)造函數(shù),而如果你直接使用operator new
時則只會進行內(nèi)存分配而不會執(zhí)行任何構(gòu)造就比如下面的代碼:
1
2
3
|
CA *p1 = new CA; //這里會分配內(nèi)存和執(zhí)行構(gòu)造函數(shù) CA *p2 = operator new ( sizeof (CA)); //這里只是執(zhí)行了普通的堆內(nèi)存分配而不會調(diào)用構(gòu)造函數(shù) |
上述的偽代碼都是在運行時通過查看匯編語言而得出的結(jié)論,我是在XCODE編譯器上查看運行的結(jié)果,有可能不同的編譯器會有一些實現(xiàn)的差異,但是不管如何要想真實的了解內(nèi)部實現(xiàn)原理還是要懂一些匯編的知識為最好。
2、placement技術(shù)
系統(tǒng)默認(rèn)的new關(guān)鍵字除了分配堆內(nèi)存外還進行構(gòu)造函數(shù)的調(diào)用。而實際中我們可能有一些已經(jīng)預(yù)先分配好的內(nèi)存區(qū)域,我們想在這些已經(jīng)分配好的內(nèi)存中來構(gòu)建一個對象。還有一種情況是不希望進行頻繁的堆內(nèi)存分配和釋放而只是對同一塊內(nèi)存進行重復(fù)的對象構(gòu)建和銷毀。就如下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
char buf1[100]; CA *p1 = (CA*)buf1; CA::CA(p1); p1->foo(); p1->m_a = 10; char *buf2 = new char [ sizeof (CA)]; CA *p2 = (CA*)buf2; CA::CA(p2); p2->foo(); p2->m_a = 20; p1->~CA(); p2->~CA(); delete [] buf2; |
可以看出代碼中buf1是棧內(nèi)存而buf2是堆內(nèi)存,這兩塊內(nèi)存區(qū)域都是已經(jīng)分配好了的內(nèi)存,現(xiàn)在我們想把這些內(nèi)存來當(dāng)做CA類的對象來使用,因此我們需要對內(nèi)存調(diào)用類的構(gòu)造函數(shù)CA::CA()才可以,構(gòu)造函數(shù)的內(nèi)部實現(xiàn)會為內(nèi)存區(qū)域填充虛表指針,這樣對象才可以調(diào)用諸如foo虛函數(shù)。但是這樣寫代碼不夠優(yōu)雅,那么有沒有比較優(yōu)雅的方法來實現(xiàn)在一塊已經(jīng)存在的內(nèi)存上來構(gòu)建對象呢? 答案就是 placement技術(shù)。 C++中的仍然是使用new
和delete
來實現(xiàn)這種技術(shù)。new
和delete
除了實現(xiàn)默認(rèn)的操作符外還重載實現(xiàn)了如下的操作符函數(shù):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
void * operator new ( size_t size, void *p) { return p; } void * operator new []( size_t size, void *p) { return p; } void operator delete ( void *p1, void *p2) { // do nothing.. } void operator delete []( void *p1, void *p2) { // do nothing.. } |
我們稱這四個運算符為 placement new
和 placement delete
。通過這幾個運算符我們就可以優(yōu)雅的實現(xiàn)上述的功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
char buf1[100]; CA *p1 = new (buf1) CA(10); //調(diào)用 operator new(size_t, void*) p1->foo(); char *buf2 = new char [ sizeof (CA)]; CA *p2 = new (buf2) CA(20); //調(diào)用 operator new(size_t, void*) p2->foo(); p1->~CA(); operator delete (p1, buf1); //調(diào)用 operator delete(void*, void*) p2->~CA(); operator delete (p2, buf2); //調(diào)用 operator delete(void*, void*) delete [] buf2; |
上面的例子里面發(fā)現(xiàn)通過placement new
可以很優(yōu)雅的在現(xiàn)有的內(nèi)存中構(gòu)建對象,而析構(gòu)時不能直接調(diào)用delete p1
, delete p2
來銷毀對象,必須人為的調(diào)用析構(gòu)函數(shù)以及placement delete
函數(shù)。并且從上面的placement delete
的實現(xiàn)來看里面并沒有任何代碼,既然如此為什么還要定義一個placement delete
呢? 答案就是C++中的規(guī)定對new和delete的運算符重載必須是要成對實現(xiàn)的。而且前面曾經(jīng)說過對delete
的使用如果帶了operator
前綴時就只是一個普通的函數(shù)調(diào)用。因此為了完成析構(gòu)以及和new操作符的匹配,就必須要人為的調(diào)用對象的析構(gòu)函數(shù)以及placement delete
函數(shù)。 除了上面舉的例子外placement
技術(shù)的使用還可以減少內(nèi)存的頻繁分配以及提升系統(tǒng)的性能。
1
2
3
4
5
6
7
8
9
|
void main() { for ( int i = 0; i < 10000; i++) { CA *p = new CA(i); p->foo(); delete p; } } |
例子里面循環(huán)10000次,每次循環(huán)都創(chuàng)建一個堆內(nèi)存對象,然后調(diào)用虛函數(shù)foo后再進行銷毀。最終的結(jié)果是程序運行時會進行10000次的頻繁的堆內(nèi)存分配和銷毀。很明顯這是有可能會影響系統(tǒng)性能的而且還有可能發(fā)生堆內(nèi)存分配失敗的情況。而如果我們借助placement
技術(shù)就可以很簡單的解決這些問題。
1
2
3
4
5
6
7
8
9
10
11
12
|
void main() { char *buf = new []( sizeof (CA)); for ( int i = 0; i < 10000; i++) { CA *p = new (buf) CA(i); p->foo(); p->~CA(); operator delete (p, buf); } delete [] buf; } |
上面的例子里面只進行了一次堆內(nèi)存分配,在循環(huán)里面都是借助已經(jīng)存在的內(nèi)存來構(gòu)建對象,不會再分配內(nèi)存了。這樣對內(nèi)存的重復(fù)利用就使得程序的性能得到非常大的提升。
3、new和delete運算符重載
發(fā)現(xiàn)一個很有意思的事情就是越高級的語言就越會將一些系統(tǒng)底層的東西進行封裝并形成一個語言級別的關(guān)鍵字來使用。比如C++中的new和delete是用于構(gòu)建和釋放堆內(nèi)存對象的關(guān)鍵字,又比如go語言中chan關(guān)鍵字是用于進行同步或者異步的隊列數(shù)據(jù)傳輸通道。 C++語言內(nèi)置默認(rèn)實現(xiàn)了一套全局new
和delete
的運算符函數(shù)以及placement new/delete
運算符函數(shù)。不管是類還是內(nèi)置類型都可以通過new/delete
來進行堆內(nèi)存對象的分配和釋放的。對于一個類來說,當(dāng)我們使用new來進行構(gòu)建對象時,首先會檢查這個類是否重載了new運算符,如果這個類重載了new運算符那么就會調(diào)用類提供的new運算符來進行內(nèi)存分配,而如果沒有提供new運算符時就使用系統(tǒng)提供的全局new運算符來進行內(nèi)存分配。內(nèi)置類型則總是使用系統(tǒng)提供的全局new運算符來進行內(nèi)存的分配。對象的內(nèi)存銷毀流程也是和分配一致的。 new和delete
運算符既支持全局的重載又支持類級別的函數(shù)重載。下面是這種運算符的定義的格式:
1
2
3
4
5
6
7
8
9
10
|
//全局運算符定義格式 void * operator new ( size_t size [, param1, param2,....]); void operator delete ( void *p [, param1, param2, ...]); //類內(nèi)運算符定義格式 class CA { void * operator new ( size_t size [, param1, param2,....]); void operator delete ( void *p [, param1, param2, ...]); }; |
對于new/delete
運算符重載我們總有如何下規(guī)則:
-
new
和delete
運算符重載必須成對出現(xiàn) -
new運算符的第一個參數(shù)必須是size_t類型的,也就是指定分配內(nèi)存的size尺寸;
delete
運算符的第一個參數(shù)必須是要銷毀釋放的內(nèi)存對象。其他參數(shù)可以任意定義。 -
系統(tǒng)默認(rèn)實現(xiàn)了
new/delete
、new[]/delete[]
、placement new / delete
6個運算符函數(shù)。它們都有特定的意義。 - 你可以重寫默認(rèn)實現(xiàn)的全局運算符,比如你想對內(nèi)存的分配策略進行自定義管理或者你想監(jiān)測堆內(nèi)存的分配情況或者你想做堆內(nèi)存的內(nèi)存泄露監(jiān)控等。但是你重寫的全局運算符一定要滿足默認(rèn)的規(guī)則定義。
-
如果你想對某個類的堆內(nèi)存分配的對象做特殊處理,那么你可以重載這個類的
new/delete
運算符。當(dāng)重載這兩個運算符時雖然沒有帶static屬性,但是不管如何對類的new/delete
運算符的重載總是被認(rèn)為是靜態(tài)成員函數(shù)。 -
當(dāng)
delete
運算符的參數(shù)>=2個時,就需要自己負責(zé)對象析構(gòu)函數(shù)的調(diào)用,并且以運算符函數(shù)的形式來調(diào)用delete
運算符。
一般情況下你不需要對new/delete
運算符進行重載,除非你的整個應(yīng)用或者某個類有特殊的需求時才會如此。下面的例子你可以看到我的各種運算符的重載方法以及使用方法:
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
//CA.h class CA { public : //類成員函數(shù) void * operator new ( size_t size); void * operator new []( size_t size); void * operator new ( size_t size, void *p); void * operator new ( size_t size, int a, int b); void operator delete ( void *p); void operator delete []( void *p); void operator delete ( void *p, void *p1); void operator delete ( void *p, int a, int b); }; class CB { public : CB(){} }; //全局運算符函數(shù),請謹(jǐn)慎重寫覆蓋全局運算符函數(shù)。 void * operator new ( size_t size); void * operator new []( size_t size); void * operator new ( size_t size, void *p) noexcept; void * operator new ( size_t size, int a, int b); void operator delete ( void *p); void operator delete []( void *p); void operator delete ( void *p, void *p1); void operator delete ( void *p, int a, int b); ....................................................... //CA.cpp void * CA::operator new ( size_t size) { return malloc (size); } void * CA::operator new []( size_t size) { return malloc (size); } void * CA::operator new ( size_t size, void *p) { return p; } void * CA::operator new ( size_t size, int a, int b) { return malloc (size); } void CA::operator delete ( void *p) { free (p); } void CA::operator delete []( void *p) { free (p); } void CA::operator delete ( void *p, void *p1) { } void CA::operator delete ( void *p, int a, int b) { free (p); } void * operator new ( size_t size) { return malloc (size); } void * operator new []( size_t size) { return malloc (size); } void * operator new ( size_t size, void *p) noexcept { return p; } void * operator new ( size_t size, int a, int b) { return malloc (size); } void operator delete ( void *p) { free (p); } void operator delete []( void *p) { free (p); } void operator delete ( void *p, void *p1) { } void operator delete ( void *p, int a, int b) { free (p); } .................................. //main.cpp int main( int argc, const char * argv[]) { char buf[100]; CA *a1 = new CA(); //調(diào)用void * CA::operator new(size_t size) CA *a2 = new CA[10]; //調(diào)用void * CA::operator new[](size_t size) CA *a3 = new (buf)CA(); //調(diào)用void * CA::operator new(size_t size, void *p) CA *a4 = new (10, 20)CA(); //調(diào)用void* CA::operator new(size_t size, int a, int b) delete a1; //調(diào)用void CA::operator delete(void *p) delete [] a2; //調(diào)用void CA::operator delete[](void *p) //a3用的是placement new的方式分配,因此需要自己調(diào)用對象的析構(gòu)函數(shù)。 a3->~CA(); CA::operator delete (a3, buf); //調(diào)用void CA::operator delete(void *p, void *p1),記得要帶上類命名空間。 //a4的運算符參數(shù)大于等于2個所以需要自己調(diào)用對象的析構(gòu)函數(shù)。 a4->~CA(); CA::operator delete (a4, 10, 20); //調(diào)用void CA::operator delete(void *p, int a, int b) //CB類沒有重載運算符,因此使用的是全局重載的運算符。 CB *b1 = new CB(); //調(diào)用void * operator new(size_t size) CB *b2 = new CB[10]; //調(diào)用void * operator new[](size_t size) //這里你可以看到同一塊內(nèi)存可以用來構(gòu)建CA類的對象也可以用來構(gòu)建CB類的對象 CB *b3 = new (buf)CB(); //調(diào)用void * operator new(size_t size, void *p) CB *b4 = new (10, 20)CB(); //調(diào)用void* operator new(size_t size, int a, int b) delete b1; //調(diào)用void operator delete(void *p) delete [] b2; //調(diào)用void operator delete[](void *p) //b3用的是placement new的方式分配,因此需要自己調(diào)用對象的析構(gòu)函數(shù)。 b3->~CB(); ::operator delete (b3, buf); //調(diào)用void operator delete(void *p, void *p1) //b4的運算符參數(shù)大于等于2個所以需要自己調(diào)用對象的析構(gòu)函數(shù)。 b4->~CB(); ::operator delete (b4, 10, 20); //調(diào)用void operator delete(void *p, int a, int b) return 0; } |
我是在XCODE上測試上面的代碼的,因為重寫了全局的new/delete
運算符,并且內(nèi)部是通過malloc來實現(xiàn)堆內(nèi)存分配的, malloc函數(shù)申明了不能返回NULL的返回結(jié)果檢測: void *malloc(size_t __size) __result_use_check __alloc_size(1)
; 因此有可能你在測試時會發(fā)生崩潰的問題。如果出現(xiàn)這個問題你可以嘗試著注釋掉對全局new/delete
重寫的代碼,再運行查看結(jié)果。 可見如果你嘗試著覆蓋重寫全局的new/delete
時是有可能產(chǎn)生風(fēng)險的。
4、對象的自動刪除技術(shù)
一般來說系統(tǒng)對new/delete
的默認(rèn)實現(xiàn)就能滿足我們的需求,我們不需要再去重載這兩個運算符。那為什么C++還提供對這兩個運算符的重載支持呢?答案還是在運算符本身具有的缺陷所致。我們知道用new關(guān)鍵字來創(chuàng)建堆內(nèi)存對象是分為了2步:1.是堆內(nèi)存分配,2.是對象構(gòu)造函數(shù)的調(diào)用。而這兩步中的任何一步都有可能會產(chǎn)生異常。如果說是在第一步出現(xiàn)了問題導(dǎo)致內(nèi)存分配失敗則不會調(diào)用構(gòu)造函數(shù),這是沒有問題的。如果說是在第二步構(gòu)造函數(shù)執(zhí)行過程中出現(xiàn)了異常而導(dǎo)致無法正常構(gòu)造完成,那么就應(yīng)該要將第一步中所分配的堆內(nèi)存進行銷毀。C++中規(guī)定如果一個對象無法完全構(gòu)造那么這個對象將是一個無效對象,也不會調(diào)用析構(gòu)函數(shù)。為了保證對象的完整性,當(dāng)通過new分配的堆內(nèi)存對象在構(gòu)造函數(shù)執(zhí)行過程中出現(xiàn)異常時就會停止構(gòu)造函數(shù)的執(zhí)行并且自動調(diào)用對應(yīng)的delete運算符來對已經(jīng)分配的堆內(nèi)存執(zhí)行銷毀處理,這就是所謂的對象的自動刪除技術(shù)。正是因為有了對象的自動刪除技術(shù)才能解決對象構(gòu)造不完整時會造成內(nèi)存泄露的問題。
當(dāng)對象構(gòu)造過程中拋出異常時,C++的異常處理機制會在特定的地方插入代碼來實現(xiàn)對對象的delete運算符的調(diào)用,如果想要具體了解情況請參考C++對異常處理實現(xiàn)的相關(guān)知識點。
全局delete
運算符函數(shù)所支持的對象的自動刪除技術(shù)雖然能解決對象本身的內(nèi)存泄露問題,但是卻不能解決對象構(gòu)造函數(shù)內(nèi)部的數(shù)據(jù)成員的內(nèi)存分配泄露問題,我們來看下面的代碼:
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
|
class CA { public : CA() { m_pa = new int ; throw 1; } ~CA() { delete m_pa; m_pa = NULL; } private : int *m_pa; }; void main() { try { CA *p = new CA(); delete p; //這句代碼永遠不會執(zhí)行 } catch ( int ) { cout << "oops!" << endl; } } |
上面的代碼中可以看到類CA中的對象在構(gòu)造函數(shù)內(nèi)部拋出了異常,雖然系統(tǒng)會對p對象執(zhí)行自動刪除技術(shù)來銷毀分配好的內(nèi)存,但是對于其內(nèi)部的數(shù)據(jù)成員m_pa
來說,因為構(gòu)造不完整就不會調(diào)用析構(gòu)函數(shù)來銷毀分配的堆內(nèi)存,這樣就導(dǎo)致了m_pa
這塊內(nèi)存出現(xiàn)了泄露。怎么解決這類問題呢? 答案你是否想到了? 那就是重載CA類的new/delete
運算符。我們來看通過對CA重載運算符解決問題的代碼:
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
|
class CA { public : CA(){ m_pa = new int ; throw 1; } //因為對象構(gòu)造未完成所以析構(gòu)函數(shù)永遠不會被調(diào)用 ~CA() { delete m_pa; m_pa = NULL; } void * operator new ( size_t size) { return malloc (size); } //重載delete運算符,把已經(jīng)分配的內(nèi)存銷毀掉。 void operator delete ( void *p) { CA *pb = (CA*)p; if (pb->m_pa != NULL) delete pb->m_pa; free (p); } private : int *m_pa; }; |
因為C++對自動刪除技術(shù)的支持,當(dāng)CA對象在構(gòu)造過程中發(fā)生異常時,我們就可以通過重載delete
運算符來解決那些在構(gòu)造函數(shù)中分配的數(shù)據(jù)成員內(nèi)存但又不會調(diào)用析構(gòu)函數(shù)來銷毀的數(shù)據(jù)成員的內(nèi)存問題。這我想就是為什么C++中要支持對new/delete
運算符在類中重載的原因吧。
到此這篇關(guān)于C++的new和delete詳解的文章就介紹到這了,更多相關(guān)C++的new和delete內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://juejin.cn/post/6844903566612627470