智能指針 shared_ptr 和 new結合使用 用make_shared函數初始化shared_ptr是最推薦的,但有的時候還是需要用new關鍵字來初始化shared_ptr。 一,先來個表格,嘮嘮new和shared_ptr | 操作 | 功能描述 | | | | | shared_ptr\ ...
智能指針 shared_ptr 和 new結合使用
用make_shared函數初始化shared_ptr是最推薦的,但有的時候還是需要用new關鍵字來初始化shared_ptr。
一,先來個表格,嘮嘮new和shared_ptr
操作 | 功能描述 |
---|---|
shared_ptr<T> p(q) | 智能指針p管理內置指針q所指向的對象;q必須指向new分配的記憶體,且能夠轉換為T*。 |
shared_ptr<T> p(u) | p從unique_ptr u那裡接管了原來u所指向對象的所有權,並將u置為空。 |
shared_ptr<T> p(q, d) | p接管了內置指針q所指的對象的所有權。q必須能轉換為T*。p將使用可調用對象d來代替delete。 |
p.reset() | 如果p是唯一指向其對象的shared_ptr,reset會釋放此對象。如果沒傳參數q,將p置為空。 |
p.reset(q) | 如果傳遞了內置指針q,會讓p指向q所指向的對象,否則會將p置為空。 |
p.reset(q, d) | 如果還傳遞了參數d,將會調用d,而不是delete來釋放q |
二,智能指針和普通指針一起使用的陷阱
void pro(shared_ptr<int> ptr){
}
shared_ptr<int> p(new int(42));//計數器為1
pro(p);//p作為參數會進行copy遞增它的計數器,在pro內部計數器是2
int i = *p;//計數器為1
cout << i << endl;
int* bad = new int(11);
//pro(bad);//編譯錯誤
pro(shared_ptr<int>(bad));//合法,但出了pro,bad所指向的記憶體會被釋放
int j = *bad;//解指針bad就會產生難以預料的結果
三,也不要使用get初始化另一個智能指針或為智能指針賦值
shared_ptr<int> p(new int(12));
int* q = p.get();
{
shared_ptr<int> tmp(q);
}//程式塊結束後,q所指向的對象被釋放
int f = *p;//解指針p就會產生難以預料的結果
cout << f << endl;
四,智能指針和異常
void f(){
shared_ptr<int> sp(new int(11));
//假設拋出了異常,而且在f中未捕獲
}//函數結束後shared_ptr自動釋放記憶體
void f1(){
int* ip = new int(12);
//假設delete語句前拋出了異常,而且在f中未捕獲
delete ip;
}//函數結束後ip所指向的記憶體沒有被釋放。
五,智能指針使用的最佳建議
- 不使用相同的內置指針初始化(或reset)多個智能指針。
- 不使用get()初始化或reset另一個智能指針。
- 不delete get()返回的指針。
- 如果使用了get()返回的指針,請牢記,當最後一個對應的智能指針被銷毀後,你的指針就變為無效了。
- 如果使用智能指針管理的資源不是new分配的記憶體,請傳遞給它一個刪除器。
小例子:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Test{
public:
Test(int d = 0) : data(d){cout << "new:" << data << endl;}
~Test(){cout << "del:" << data << endl;}
private:
int data;
};
void my_deleter(Test* t){
cout << "my_deleter is work" << endl;
}
void pro(shared_ptr<int> ptr){
}
int main(){
//test1 reset
/*
Test* tp = new Test(1);
shared_ptr<Test> stp(tp);
shared_ptr<Test> stp1(stp);
stp.reset();
cout << stp << endl;
*/
//test2 自定義刪除器
/*
Test* tp = new Test(1);
//不會調用Test的析構函數了,只調用my_deleter函數
shared_ptr<Test> stp(tp, my_deleter);
shared_ptr<Test> stp1(stp);
cout << stp.use_count() << endl;
Test* tp1 = new Test(2);
stp1.reset(tp1, my_deleter);
*/
//test3 不要混用普通指針和智能指針
/*
shared_ptr<int> p(new int(42));//計數器為1
pro(p);//p作為參數會進行copy遞增它的計數器,在pro內部計數器是2
int i = *p;//計數器為1
cout << i << endl;
int* bad = new int(11);
//pro(bad);//編譯錯誤
pro(shared_ptr<int>(bad));//合法,但出了pro,bad所指向的記憶體會被釋放
int j = *bad;//解指針bad就會產生難以預料的結果
*/
//test4 get的錯誤使用
/*
shared_ptr<int> p(new int(12));
int* q = p.get();
{
shared_ptr<int> tmp(q);
}//程式塊結束後,q所指向的對象被釋放
int f = *p;//解指針p就會產生難以預料的結果
cout << f << endl;
*/
}