>>> 背景
最近在看一些C++資料的過程中,說到在初始化列表中使用關鍵字new來分配新內存不是異常安全的,應該使用運算符new。這里就引發了我對C++ new的全新認識。
class A {
public:
A(int a) : px(new int(a)) {} // 當然這里基礎類是不會異常的
int* px;
};
>>> 內容
首先我們來回憶一下最常規的new用法。首先創建一個測試類A,并在其構造和析構函數里面打印提示語句。可以發現,在new一個A對象的時候調用了構造函數,在delete一個A對象的時候析構了此對象。而且與C標準庫中的malloc函數相比,new關鍵字不需要知道分配的字節數,而是對類型大小做了自動推斷,顯然更加方便。
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.
但是方便的代價就是隱藏了很多細節,從而可能導致使用者在沒有充分理解的情況下造成誤用。其實關鍵字new做了非常多的操作。
這里首先給出3個概念,分別是:關鍵字new、操作符new和放置new(或者說,keywords new、operator new、placement new)。它們之間的關系大概如下所示。
當我們使用關鍵字new去創建一個對象時,會首先根據A類型推斷出需要申請的內存字節數,然后再交給operator new去按字節數申請一塊可用的內存(否則拋出異常),最后調用類的構造函數創造一個對象保存在申請的這段內存中。
而placement new起到的作用是在分配好的內存上創建對象,和operator new有那么一點互補的意思。placement new的引入是為了避免一些頻繁的內存申請和回收操作,可以專門申請一塊內存做重復的計算,而不是需要一個對象就申請一個內存,從而提高效率。
下面是一個比較綜合的例子,來表現這些new之間不同。可以看到,我們首先通過operator new來創建一塊能夠容納3個A對象的內存空間,然后通過placement new來在這個申請好的內存空間上創建對象,最后使用operator delete把申請的空間銷毀。
可以看到operator new不會調用構造函數,operator delete也不會調用析構函數。通過placement new配合起始指針的偏移,可以逐個在新內存上創建有意義的數據對象。
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
>>> 小結
可以看出,C++在內存分配引入了不少的概念,operator new和operator delete都是可以被自定義類重載的,這就給予了程序員很好的自由度。除了使用new和delete來管理內存外,C++還引入了更為復雜的allocator(或分配器)的概念。
-
分配器
+關注
關注
0文章
195瀏覽量
25832 -
C++語言
+關注
關注
0文章
147瀏覽量
7027
發布評論請先 登錄
相關推薦
評論