一,內存
靜態內存,棧內存,堆內存
①靜態內存
存儲局部static對象和類的static對象以及定義在任何函數之外的變量
②棧內存
棧內存用於保存定義在函數體內非static對象。
③堆內存
運行需要創建時,才申請的內存空間,只有當程序結束時,才回收,也就是說我們如果不需要這個對象時,我們必須手動釋放這塊內存空間,否則造成內存泄漏
④智能指針
①智能指針可以在我們不需要動態申請的內存時,自動把這些內存歸還給系統,防止了內存泄漏,
而且我們通常會忘記delete動態申請的內存,
②當智能指針超出器范圍時,就會自動析構,比如在代碼塊中定義的智能指針,程序執行到代碼塊之外就會自動析構智能指針
二,shared_ptr
shared_ptr允許多個指針同時指向同一個對象,默認初始化方式就是置為nullptr,使用前必須檢查他是否是nullptr
if(p && p->member_fun())
{
// code
}
①聲明,初始化 (假設指針指向的對象類為T)
最安全的分配和使用動態對象的方式是調用make_shared(args_list…)函數
shared_ptr p = make_shard(args…)//相當於調用T對象的構造函數,args是其構造函數的參列 表,(如果僅聲明就是調用默認構造器,直接置為nullptr)
注意:如果shared_ptr對象的創建不可以用“=”直接賦值!!!,因為shared_ptr的構造器是explicit修飾的,指針不可以通過=直接轉換為智能指針對象!!!,
初始化的一些常見問題
shared_ptr<int> p1 = new int(1024);錯誤,因為shared_ptr的單參數構造器有explicit修飾,不能從內置類型直接轉換成為對象!!,所以此行編譯報錯!!
shared_ptr<int> p1(new int(1024));正確,調用了單參數構造器進行初始化,傳入了指針初始化
shared_ptr<int> f(int n)
{
return new int(n);同一個錯誤原因,explicit修飾了shared_ptr的構造器,無法從內置類型直接變成對象
}
②shared_ptr的拷貝和賦值,計數器
計數器遞增的三種情況:
①用shared_ptr指針給同類的指針賦值,初始化
②作為函數實參傳入函數
③作為函數返回值
計數器遞減:
①指針指向了另外一種對象(可能是T的子類),也就是發生在智能指針的賦值之間
②智能指針被銷毀了,例如智能指針作為棧變量,出了代碼塊之后就被銷毀了
特別的:當引用計數器為0時,自動釋放智能指針指向的內存空間
也就是說當只有一個智能指針指向這塊內存時,p被銷毀,就會自動釋放p指向的內存
③shared_ptr的使用:
設計一個類叫Obj,Obj的一個成員就是shared_ptr指針,然后創建多個Obj的實例,初始化的時候就
把需要共享的對象傳進去,讓shared_ptr指向同一個共享對象,就實現了共享,當沒有對象的shared_ptr
指向這個共享對象時,智能指針將自動釋放動態的共享對象的內存並銷毀它。
④智能指針的陷阱
Ⅰ不使用相同的內置指針初始化或者reset多個智能指針,最好是用智能指針初始化智能指針
Ⅱ不delete get()返回的指針
Ⅲ不用get()初始化或reset另一個智能指針
Ⅳ使用get返回的指針,當唯一一個指向動態對象的智能指針銷毀后,get指針也是失效了
Ⅴ當你使用智能指針管理的資源不是new分配時,記得傳遞一個刪除器給智能指針
三,unique_ptr
unique_ptr則是獨占這個對象,只能有一個指針指向這個對象
四,動態分配的數組
注:使用new分配的數組,只是返回了一個數組元素類型的指針,並沒有得到一個數組對象,
所以我們不可以對動態數組使用begin和end,以及范圍for
unique_ptr,shared_ptr和數組
①unique_ptr沒有重載operator*()所以,要使用unique_ptr指向的數組的話,就只能使用operator[]來
訪問數組元素了,
如圖:
#include <iostream>
#include<memory>
using namespace std;
int main()
{
// shared_ptr<int[]> ps(new int[1000]);由於默認是delete,所以禁止new []
unique_ptr<int[]> ps(new int[99]);
for(int i = 0 ; i < 10 ; i++)
ps[i] = 10 - i;用operator[]訪問數組元素,同時也沒有operator*和operator++等
for(int i = 0 ; i < 10 ; i++)
cout << ps[i] << endl;
return 0;
}
五,總結的一些警告
new與new[]
①不要讓auto_ptr和shared_ptr指向new[]申請的動態內存(除非為智能指針定義一個刪除器)
原因:auto_ptr 和 shared_ptr 的默認釋放內存方式是delete,如果動態對象是以new[] 形式創建的,比如數組,
就不要使用auto_ptr和shared_ptr,否則就會導致以delete形式去釋放new[]申請的內存
一句話概括就是auto_ptr和shared_ptr只能指向new(除非為智能指針定義一個刪除器)
② unique_ptr可以指向 new和new[] 申請的動態內存
