005shared_ptr常用操作與使用陷阱
#include<iostream>
#include<cstdlib>
#include<string>
#include<vector>
#include <memory>
using namespace std;
//測試類
class CT:public enable_shared_from_this<CT>
{
public:
shared_ptr<CT>getself()
{
//return shared_ptr<CT>(this);
return shared_from_this();//enable_shared_from_this類中的方法
}
};
class B;//聲明B類
class A
{
public:
shared_ptr<B> pm_b;
//解決辦法:
//weak_ptr<B>pm_b''
~A()
{
cout << "A的析構函數" << endl;
}
};
class B
{
public:
shared_ptr<A> pm_a;
~B()
{
cout << "B的析構函數" << endl;
}
};
//A類和B類循環引用
shared_ptr<int>createFunction(int value)
{
return make_shared<int>(value);//返回一個shared_ptr指針
}
//
//void myFunction(int value)
//{
// shared_ptr<int>pTem = createFunction(100);
// return;//離開作用域後,pTem所指向的內存會被自動釋放
//}
shared_ptr<int> myFunction(int value)
{
shared_ptr<int>pTem = createFunction(100);
return pTem;//返回局部對象
}
void myFuncion02(shared_ptr<int>ptr)
{
return;
}
int main(void)
{
//(1)
myFunction(100);
shared_ptr<int>p1 = myFunction(10);//如果不用變量來接受,返回的局部變量就會銷燬。
//2.1慎用裸指針
int*p = new int(100);
//myFuncion02(p);//error,不允許隱式類型轉化
myFuncion02(shared_ptr<int>(p));//參數是臨時的shared_ptr,用一個裸指針顯式的構造
*p = 22;//這一段內存已經被回收,臨時對象傳遞給函數會是個局部量,函數運行完畢會釋放。
//內存對象的管理已經交給智能指針,這裏不要再使用裸指針
//不要使用裸指針初始化多個shared_ptr--會導致內存釋放多次 p3,p4無關
/*int*p2 = new int(200);
shared_ptr<int>p3(p2);
shared_ptr<int>p4(p2);*/
//更改方法:
shared_ptr<int>p3(new int(200));
shared_ptr<int>p4(p3);//這種寫法是ok的,用的是同一個控制塊,指向同一塊內存塊
//2.2慎用get()函數的返回值--返回指正對象指針的裸指針,不能刪除
shared_ptr<int>p5(new int(234));
int *p6 = p5.get();
//delete p;
//不可以將其他智能指針綁定到get返回的裸指針上
//shared_ptr<int>p7(p6);//兩個智能指針沒有關係,當一個釋放的時候,另一個再釋放一次就會出錯
//每個智能指針用裸指針創建,他們之間的引用是相互分離的。
//3.不要把類對象指針(this)作爲shared_ptr返回,改用enable_shared_from_this返回
shared_ptr<CT>Pct1(new CT);
//shared_ptr<CT>Pct2(Pct1);//兩個強引用,使用同一個控制塊
shared_ptr<CT>pct3 = Pct1->getself();//兩個智能指針之間不是使用同一個控制塊,沒有關係.有一種使用裸指針初始化智能指針的
//解決辦法:c++標準庫中的類模板enalbe_shared_from_this,返回的是一個智能指針
//2.4避免循環引用
shared_ptr<A> pca(new A);
shared_ptr<B> pcb(new B);
pca->pm_b = pcb;//指向pcb的有兩個強引用
pcb->pm_a = pca;//指向pca的有兩個強引用
/*
* 最終所有的內存都沒有釋放,因爲對象互相包含對象,每個對象的強引用都是2,都不能釋放。
* 解決辦法:
* 只需要將其中一個變爲弱引用即可。
*/
//3.2移動語義
shared_ptr<int>p7(new int(1000));
shared_ptr<int>p8(std::move(p1));//移動構造,移動構造一個新的智能指針對象p8,p7不再指向1000,
//引用計數還是1
//43.優先使用make_shared,編譯器有優化這個函數。
shared_ptr<string>p9(new string("jisuan"));
/*
* 分配兩次內存,一次存儲jisuan,一次用來存放p9的控制塊
*/
auto p10 = make_shared<string>("jisuajis");//只分配一次內存
system("pause");
return 0;
}
/*
*(1)shared_ptr使用場景-
* 從函數中return shared_ptr類型指針
*
*
*(2)智能指針是用錯誤分析
* 2.1慎用裸指針--使用裸指針賦值給智能指針後,內存管理的責任就交給智能指針,就不應該再使用裸指針訪問內存了。
* 不用使用裸指針初始化多個shared_ptr
* 2.2慎用get()函數的返回值
* 返回智能對象的裸指針不能delete,否則會異常
* 永遠不要用get()得到的裸指針來初始化另一個智能指針。
* 3.不要把類對象指針(this)作爲shared_ptr返回,改用enable_shared_from_this返回
* 返回對象的this指針,使用public繼承enable_shared_from_this<>,然後返回shared_from_this()
* 原理:enable_shared_from_this中有一個弱指針weak_ptr,通過這個弱指針監視this指針。
* 在我們調用shared_from_this()方法的時候,這個方法內部調用了weak_ptr的lock()方法,返回shared_ptr指針計數—+1
* 並返回shared_ptr指針
* 2.4避免循環引用
*
*(3)性能說明
*3.1尺寸問題
* shared_ptr,weak_ptr的尺寸都是裸指針的2倍。
* 創建控制塊的時機:
* 1.make_shared,分配並初始化一個對象,返回指向此對象的shared_ptr
* 2.用裸指針來創建愛女一個shared_ptr對象時候,使用裸指針會產生多個控制塊,詳見2.2
*
*3.2移動語義
*移動肯定比賦值塊,複製要增加引用計數,但是移動不會增加引用計數。
*
*(4)補充說明和使用建議
* 1.分配器等問題沒有講解。
* 2.智能指針也不是刻意隨心所欲的使用,謹慎使用。
* 3.優先使用make_shared,編譯器有優化這個函數。
*
*/