在c++中,動態記憶體的管理是用一對運算子完成的:new和delete,new:在動態記憶體中為物件分配一塊空間並返回乙個指向該物件的指標,delete:指向乙個動態獨享的指標,銷毀物件,並釋放與之關聯的記憶體。
動態記憶體管理經常會出現兩種問題:一種是忘記釋放記憶體,會造成記憶體洩漏;一種是尚有指標引用記憶體的情況下就釋放了它,就會產生引用非法記憶體的指標。
智慧型指標是儲存動態分配(堆)物件指標的類,用於生存週期控制,能夠確保在離開指標所在作用域時,自動正確地銷毀動態分配的物件,防止記憶體洩露。它的一種通用實現技術是使用引用計數,每使用一次,內部的引用計數加1,每析構一次,內部引用計數減1,減為0時,刪除所指向的堆記憶體。
智慧型指標主要用於管理在堆上分配的記憶體,它將普通的指標封裝為乙個棧物件。當棧物件的生存週期結束後,會在析構函式中釋放掉申請的記憶體,從而防止記憶體洩漏。c++ 11中最常用的智慧型指標型別為shared_ptr,它採用引用計數的方法,記錄當前記憶體資源被多少個智慧型指標引用。該引用計數的內存在堆上分配。當新增乙個時引用計數加1,當過期時引用計數減一。只有引用計數為0時,智慧型指標才會自動釋放引用的記憶體資源。對shared_ptr進行初始化時不能將乙個普通指標直接賦值給智慧型指標,因為乙個是指標,乙個是類。可以通過make_shared函式或者通過建構函式傳入普通指標。並可以通過get函式獲得普通指標。
c++ 11 提供了3種智慧型指標:std::shared_ptr、std::unique_ptr、std::weak_ptr,使用時引用標頭檔案 。
因為智慧型指標是乙個類,當超出了類的例項物件的作用域時,會自動呼叫物件的析構函式,析構函式會自動釋放資源。所以智慧型指標的作用原理就是在函式結束時自動釋放記憶體空間,不需要手動釋放記憶體空間。
std::shared_ptr 使用引用計數,每乙個shared_ptr 的拷貝都指向相同的記憶體。在最後乙個shared_ptr 析構時,記憶體才會被釋放。
每個 shared_ptr 物件在內部指向兩個記憶體位置:
1、指向物件的指標。
2、用於控制引用計數資料的指標。
共享所有權如何在參考計數的幫助下工作:
1、當新的 shared_ptr 物件與指標關聯時,則在其建構函式中,將與此指標關聯的引用計數增加1;
2、當任何 shared_ptr 物件超出作用域時,則在其析構函式中,它將關聯指標的引用計數減1。如果引用計數變為0,則表示沒有其他 shared_ptr 物件與此記憶體關聯,在這種情況下,它使用delete函式刪除該記憶體
多個 shared_ptr 物件可以共同託管乙個指標 p,當所有曾經託管 p 的 shared_ptr 物件都解除了對其的託管時,就會執行delete p
。
#include #include using namespace std;
class a
; ~a()
};int main()
輸出結果:
2,2,223
2 destructed
end5 destructed
4 destructed
3 destructed
(1)建構函式初始化
std::shared_ptrpointer(new int(1));//建構函式初始化智慧型指標
std::shared_ptrpointer1 = pointer;//智慧型指標給智慧型指標賦值
(2)std::make_shared 初始化
std::shared_ptrp3 = std::make_shared(1);
std::cout << "p3 = " << *p3 << std::endl;
(3)reset 初始化
使用reset 方法初始化智慧型指標
std::shared_ptrpointer;
pointer.reset(new int(1));
當需要獲取智慧型指標時,可以通過get方法來返回原始指標。
std::shared_ptrp3 = std::make_shared(1);
std::cout << "p3 = " << *p3 << std::endl;
int *ptr = p3.get();
std::cout << "ptr = " << *ptr << std::endl;
智慧型指標初始化可以指定刪除器。
如下所示,當p 的引用計數為0時,自動呼叫刪除器deleteintptr 來釋放物件的記憶體。
void deleteintptr(int* p)
int main()
也可以用 lambda 表示式的形式
std::shared_ptrpointer1(new int(1), (int* p) );
錯誤用法:
(1)不能將乙個原始的指標直接賦值給乙個智慧型指標
std::shared_ptrp = new int(1);//錯誤用法
(2) 不能用乙個原始指標初始化多個shared_ptr
int* ptr = new int;
shared_ptrp1(ptr);
shared_ptrp2(ptr);//錯誤用法,不能用乙個原始指標初始化化多個 shared_ptr
(3)要避免迴圈引用,迴圈引用會導致記憶體洩露
struct a;
struct b;
struct a
};struct b
};int main()
迴圈引用導致 ap和bp 的引用計數為2,在離開作用域之後,ap和bp 的引用計數減為1,並不會減為0,導致兩個指標都不會被析構,產生了記憶體洩露。
unique_ptr 是乙個獨佔型的智慧型指標,它不允許其他的智慧型指標共享其內部的指標,不允許通過賦值將乙個unique_ptr 賦值給另外乙個unique_ptr。
可以通過std::move 來轉移其他的unique_ptr 。
std::unique_ptrmyptr(new int(1));//okey
使用std::move 轉移,如下所示,轉移之後 myptr 不能指向原來的物件。
std::unique_ptrmyptr(new int(1));//okey
std::unique_ptrmyptr1 = std::move(myptr);//使用std::move 來轉移到其他的unique_ptr
錯誤用法:
std::unique_ptrmyptr1 = myptr;//錯誤用法,unique_ptr 智慧型指標不能賦值給另外乙個 unique_ptr
如果希望只有乙個智慧型指標管理資源或者管理陣列就用unique_ptr,如果希望多個智慧型指標管理同乙個資源就用share_ptr。弱引用指標weak_ptr 是用來監視shared_ptr 的,不會使引用計數加1,它也不管理shread_ptr 內部的指標,主要用來監視shared_ptr 的生命週期。
(1)通過use_count() 來獲得當前觀測資源的引用計數。
(2)通過expired() 方法來判斷所觀測的資源是否已經被釋放。
(3)通過lock 方法來獲取所監視的shared_ptr。
參考:c++11 - std::shared_ptr初始化的幾種方式:
c++ 智慧型指標 shared_ptr 詳解與示例:
c++11 shared_ptr(智慧型指標)詳解:
std::shared_ptr:
C 動態記憶體與智慧型指標
qq 1841545843 郵箱 jiaxx903 163.com 靜態記憶體用來儲存區域性 static 物件 類的 static 資料成員,以及定義在任何函式之外的變數。棧記憶體用來儲存定義在函式之內的 static 物件。除了棧記憶體和靜態記憶體外,每個程式還擁有乙個記憶體池,這部分稱之為 堆...
c 動態記憶體與智慧型指標
目前為止我們學過靜態記憶體和棧記憶體,分配在其中的物件由編譯器自動建立和銷毀,靜態記憶體 用來儲存區域性static物件 類的static資料成員 以及定義在任何函式體之外的變數。在物件使用之前分配,程式結束時銷毀。棧記憶體 用來儲存定義在函式內的非static物件。僅在物件定義的程式塊執行時存在,...
動態記憶體與智慧型指標
動態記憶體與智慧型指標 靜態記憶體用來儲存區域性static物件 類static資料成員以及定義在任何函式之外的變數 全域性變數 棧記憶體用來儲存定義在函式內的非static物件。分配在靜態或棧記憶體中的物件由編譯器自動建立和銷毀。對於棧物件,僅在其定義的程式塊執行時才存在 static物件在使用之...