1.1 動態記憶體和使用原因
程式使用記憶體大概可以分為「堆疊全常代」[1],和智慧型指標相關的是堆區,堆(heap)在c++中也被稱為自由空間。自由空間的「自由」應該理解為程式設計師自己編寫的自主控制其生命週期的空間,申請的空間大小相對寬裕[2]。
出於三個原因要使用動態記憶體
除此,智慧型指標是異常安全的。即異常退出也會成功釋放對應記憶體。
1.2 管理動態記憶體的方法
雖然c++程式設計師可以使用new和delete完成對動態記憶體的申請和釋放,但是該方式不正確使用會出現「記憶體洩漏」、「多次釋放同一空間」等問題,前者忘記釋放,後者無意多次釋放。為了減少這種管理動態記憶體上出錯概率,智慧型指標就出現了!c++有四個智慧型指標分別是:auto_ptr
,unique_ptr
,shared_ptr
,weak_ptr
, 其中後三個是c++11支援,auto_ptr於c++17被移除[3]。
#include
中可以找到這些智慧型指標的定義,主要
template
<
class
y>
explicit
shared_ptr
( y* ptr )
;template
<
classy,
class
deleter
>
shared_ptr
( y* ptr, deleter d )
;//刪除器版本
template
<
classt,
class
deleter
= std::default_delete
>
class
unique_ptr
;template
<
classt,
class
deleter
>
class
unique_ptr
], deleter>
;template
<
class
t>
class
weak_ptr
;template
<
class
t>
class
auto_ptr
;template
<
>
class
auto_ptr
<
void
>
;
shared_ptr和unique_ptr
都能夠幫助程式設計師管理好記憶體釋放時機,但是前者指的是可以由多個shared_ptr管理,後者只能通過乙個unique_ptr管理。
unique_ptr因為不用管理引用計數,效率可以和原始指標相媲美[5]。
std::shared_ptr sp = std::make_shared(2
,3);
std::shared_ptr
ssp(sp)
;std::shared_ptr
sssp
(ssp)
;std::cout
;std::unique_ptr up = std::make_unique(3
,4);
在unique_ptr和shared_ptr中雖可通過原始指標進行直接構造(但是這個函式是explict的),但是標準庫建議使用make_shared make_unique進行「安全的」構造由智慧型指標管理的物件。為什麼是安全的?看看這個例子就可以解開你的疑惑:
std::unique_ptr up;
a* pa =
new a;
//!!!暴露了動態記憶體的介面,任何乙個指標都可以通過這個釋放記憶體
up = std::unique_ptr
(pa)
;//up接管了記憶體
std::unique_ptr upup;
upup = std::unique_ptr
(pa)
;//upup接管了記憶體
//離開作用域,同乙個pa指向的記憶體釋放了兩次,嚴重錯誤
shared_ptr之所以叫做共享,是因為對於不止自己管理了這份資源,還有其他shared_ptr參與了管理;unique_ptr之所以叫做獨一無二的,是因為其擁有對資源的完全把控,不允許其他指標使用這份資源。unique_ptr通過禁止拷貝、賦值來實現獨佔功能。
為什麼智慧型指標有make_shared和make_unique方法?看看這個例子你就知道了:
int
main()
如果你是通過這個方式初始化的智慧型指標,裸指標暴露了自己的位置,導致可能有多有unique_ptr指向了同一塊記憶體,從而進行兩次釋放資源。這個結論對於shared_ptr也適用:
std::shared_ptr up;
a* pa =
new a;
up = std::shared_ptr
(pa)
;std::shared_ptr upup;
upup = std::shared_ptr
(pa)
;
所以說,使用智慧型指標時最好使用安全的make_shared和make_unique(c++14)方法。
和std::shared_ptr(new t(args...))
相比,使用make_shared函式:
[1] 堆區,棧區,全域性(靜態)區,常量區和**區。
[2] 關於棧、堆、靜態儲存區最大可分配大小的**.
[3] 詳解c++11智慧型指標.
[4] auto_ptr沒有管理好拷貝操作,會導致多次釋放記憶體,因此在unique_ptr將拷貝禁止了。但是臨時右值和std::move可以實現類似於「拷貝的操作」
[5] 為何優先選用unique_ptr而不是裸指標?
智慧型指標(一)
c 程式設計中使用堆記憶體是非常頻繁的操作,堆記憶體的申請和釋放都由程式設計師自己管理。管理是麻煩點 e.g.手動釋放等 但無傷大雅,勉強可以接受 但要命的是,容易出問題 為了解決該問題,c 11 引入智慧型指標概念使記憶體管理變得更為方便,且不易出錯 智慧型指標包含在標頭檔案中,包括 shared...
智慧型指標 強弱智慧型指標
在平時編寫 的時候經常會用到new來開闢空間,而我們開闢出來的空間必須得手動去delete他,但是如果程式設計師忘記去手動釋放那邊會出現乙個麻煩的問題,記憶體洩漏!或者是一塊記憶體被多個函式同時使用時,如果其中乙個函式不知道還有其他人也在使用這塊記憶體而釋放掉的話同樣也會引起程式的崩潰。引起記憶體洩...
c 智慧型指標的問題 智慧型指標初探(一)
為什麼要有智慧型指標 在c 中,動態記憶體的管理一般是用一對運算子完成的 new和delete。new 在動態記憶體中為物件分配一塊空間並返回乙個指向該物件的指標。delete 指向乙個動態獨享的指標,銷毀物件,並釋放與之關聯的記憶體。使用new和delete動態記憶體管理經常會出現問題 忘記釋放記...