C++之動態內存與智能指針

頭文件

#include <memory>

shared_ptr和unique_ptr支持的操作

在這裏插入圖片描述

shared_ptr

  • 一旦一個shared_ptr 的計數器變爲0,它就會自動釋放自己所管理的對象
  • 程序使用動態內存出於以下三種原因之一:
    ① 程序不知道自己需要使用多少對象
    ② 程序不知道所需對象的準確類型
    ③ 程序需要在多個對象間共享數據
  • 定義和改變shared_ptr的其他方法
    在這裏插入圖片描述
  • 在發生異常的時候智能指針會檢查引用計數自動釋放,而顯式指針如果異常發生在delete前則不會釋放會造成內存泄漏。
  • 使用智能指針解決一些類沒有析構函數導致異常終止無法關閉的問題,例如,假定我們正在使用一個C和C++都在使用的網絡庫:
void f(destination &d){
	connection c = connect(&d);
	//使用連接
	//如果我們在f退出前忘記調用disconnect,就無法關閉c了。
}

這樣我們可以使用自己的釋放操作,將connection對象綁定智能指針,對其進行模擬析構

void end_connection(connection *p){
	disconnect(*p);
}
void f(destination &d){
	connection c = connect(&d);
	shared_ptr<connection> p(&c,end_connection);
	//使用連接
	//當f退出時,即使由於異常而退出,connection也會被正確關閉
}

或者

void f(destination &d){
	connection c = connect(&d);
	shared_ptr<connection> p(&c,[](connection *p){disconnect(*p);});
	//使用連接
	//當f退出時,即使由於異常而退出,connection也會被正確關閉
}
  • 智能指針一些注意點:
    • 不使用相同的內置指針值初始化多個智能指針
    • 不delete get() 返回的指針
    • 不使用get()初始化或reset另一個智能指針
    • 如果你使用get()返回的指針,記住當最後一個對應的智能指針銷燬後,你的指針就變爲無效了。
    • 如果你使用智能指針管理的資源不是new分配的內存,記住傳遞給它一個刪除器。\

unique_ptr

  • unique_ptr只能直接初始化,沒有mark_shared這種操作
unique_ptr<int> p(new int(42));
  • 由於一個unique_ptr擁有它指向的對象,因此unique_ptr不支持普通的拷貝或賦值操作
    在這裏插入圖片描述
  • 雖然我們不能拷貝或複製unique_ptr,但可以調用release或reset將指針的所有權從一個(非const)unique_ptr轉移給另一個unique:
unique_ptr<string> p2(p1.release());
unique_ptr<string> p3(new string("Test"));
p2.reset(p3.release());
  • 使用unique實現自定義刪除器
void end_connection(connection *p){
	disconnect(*p);
}
void f(destination &d){
	connection c = connect(&d);
	unique_ptr<connection,decltype(end_connection)*> p(&c,end_connection);
	//使用連接
	//當f退出時,即使由於異常而退出,connection也會被正確關閉
}

weak_ptr

  • weak_ptr是一種不控制所指向對象生存期的智能指針,它指向由一個shared_ptr管理的對象。將一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數。一旦最後一個指向對象的shared_ptr被銷燬,對象就會被釋放。即使有weak_ptr指向對象,對象也還是會被釋放。因此,weak_ptr的名字抓住了這種智能指針“弱”共享對象的特點。
    在這裏插入圖片描述
  • 如何使用weak_ptr訪問對象:
if(shared_ptr<int> np = wp.lock()){  //如果np不空則條件成立
	//在if中,np與p共享對象
}

在這段代碼中,只有當lock調用返回true時我們纔會進入if語句體。在if中,使用np訪問共享對象是安全的。

動態數組

  • 創建和釋放動態數組
int *pia = new int[10];
int *pia1 = new int[10](); //初始化爲0;
delete []pa; 
  • 使用unique_ptr維護動態數組(shared_ptr不直接支持)
//使用unique_ptr
unique_ptr<int[]> up(new int[10]);
up.release(); //自動用delete[]銷燬其指針

//爲了使用shared_ptr,必須提供一個刪除器
shared_ptr<int> sp(new int[10],[](int *p){delete[] p;});
sp.reset();

allocator類

  • new有一些靈活性上的侷限,其中一方面表現在它將內存分配和對象構造組合在了一起。類似的,delete將對象析構和內存釋放組合在了一起。我們分配單個對象時,通常希望將內存分配和對象初始化組合在一起。因爲在這種情況下,我們幾乎肯定知道對象應該有什麼值。但是分配一大塊內存時,我們通常計劃在這塊內存上按需構造對象。在此情況下,我們希望將內存和對象構造分離。
  • 使用alloctor類分配空間
allocator<string> alloc;
auto const p = alloc.allocate(n);

在這裏插入圖片描述
·

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章