>>> 背景
最近在看一些C++資料的過(guò)程中,說(shuō)到在初始化列表中使用關(guān)鍵字new來(lái)分配新內(nèi)存不是異常安全的,應(yīng)該使用運(yùn)算符new。這里就引發(fā)了我對(duì)C++ new的全新認(rèn)識(shí)。
class A {
public:
A(int a) : px(new int(a)) {} // 當(dāng)然這里基礎(chǔ)類是不會(huì)異常的
int* px;
};
>>> 內(nèi)容
首先我們來(lái)回憶一下最常規(guī)的new用法。首先創(chuàng)建一個(gè)測(cè)試類A,并在其構(gòu)造和析構(gòu)函數(shù)里面打印提示語(yǔ)句。可以發(fā)現(xiàn),在new一個(gè)A對(duì)象的時(shí)候調(diào)用了構(gòu)造函數(shù),在delete一個(gè)A對(duì)象的時(shí)候析構(gòu)了此對(duì)象。而且與C標(biāo)準(zhǔn)庫(kù)中的malloc函數(shù)相比,new關(guān)鍵字不需要知道分配的字節(jié)數(shù),而是對(duì)類型大小做了自動(dòng)推斷,顯然更加方便。
class A {
public:
A(int a) : _a(a) {
cout < < "object A(" < < _a < < ") is constructed.n";
}
~A() {
cout < < "object A(" < < _a < < ") is destructed.n";
}
int _a;
};
int main() {
A* obj = new A(1);
delete obj;
return 0;
}
object A(1) is constructed.
object A(1) is destructed.
但是方便的代價(jià)就是隱藏了很多細(xì)節(jié),從而可能導(dǎo)致使用者在沒有充分理解的情況下造成誤用。其實(shí)關(guān)鍵字new做了非常多的操作。
這里首先給出3個(gè)概念,分別是:關(guān)鍵字new、操作符new和放置new(或者說(shuō),keywords new、operator new、placement new)。它們之間的關(guān)系大概如下所示。
當(dāng)我們使用關(guān)鍵字new去創(chuàng)建一個(gè)對(duì)象時(shí),會(huì)首先根據(jù)A類型推斷出需要申請(qǐng)的內(nèi)存字節(jié)數(shù),然后再交給operator new去按字節(jié)數(shù)申請(qǐng)一塊可用的內(nèi)存(否則拋出異常),最后調(diào)用類的構(gòu)造函數(shù)創(chuàng)造一個(gè)對(duì)象保存在申請(qǐng)的這段內(nèi)存中。
而placement new起到的作用是在分配好的內(nèi)存上創(chuàng)建對(duì)象,和operator new有那么一點(diǎn)互補(bǔ)的意思。placement new的引入是為了避免一些頻繁的內(nèi)存申請(qǐng)和回收操作,可以專門申請(qǐng)一塊內(nèi)存做重復(fù)的計(jì)算,而不是需要一個(gè)對(duì)象就申請(qǐng)一個(gè)內(nèi)存,從而提高效率。
下面是一個(gè)比較綜合的例子,來(lái)表現(xiàn)這些new之間不同??梢钥吹?,我們首先通過(guò)operator new來(lái)創(chuàng)建一塊能夠容納3個(gè)A對(duì)象的內(nèi)存空間,然后通過(guò)placement new來(lái)在這個(gè)申請(qǐng)好的內(nèi)存空間上創(chuàng)建對(duì)象,最后使用operator delete把申請(qǐng)的空間銷毀。
可以看到operator new不會(huì)調(diào)用構(gòu)造函數(shù),operator delete也不會(huì)調(diào)用析構(gòu)函數(shù)。通過(guò)placement new配合起始指針的偏移,可以逐個(gè)在新內(nèi)存上創(chuàng)建有意義的數(shù)據(jù)對(duì)象。
int main() {
A* mempool = (A*)operator new(sizeof(A) * 3);
cout < < "Memory is allocated!n";
A* obj1 = new(mempool) A(1);
A* obj2 = new(mempool + 1) A(2);
A* obj3 = new(mempool + 2) A(3);
cout < < obj1- >_a < < endl;
cout < < obj2- >_a < < endl;
cout < < obj3- >_a < < endl;
operator delete(mempool);
cout < < obj1- >_a < < endl;
cout < < obj2- >_a < < endl;
cout < < obj3- >_a < < endl;
return 0;
}
Memory is allocated!
object A(1) is constructed.
object A(2) is constructed.
object A(3) is constructed.
1
2
3
35134640
0
1448320
>>> 小結(jié)
可以看出,C++在內(nèi)存分配引入了不少的概念,operator new和operator delete都是可以被自定義類重載的,這就給予了程序員很好的自由度。除了使用new和delete來(lái)管理內(nèi)存外,C++還引入了更為復(fù)雜的allocator(或分配器)的概念。
-
分配器
+關(guān)注
關(guān)注
0文章
194瀏覽量
25795 -
C++語(yǔ)言
+關(guān)注
關(guān)注
0文章
147瀏覽量
7012
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論