智能指針 shared_ptr 使用 上一篇 "智能指針是啥玩意" ,介紹了什麼是智能指針。 這一篇簡單說說如何使用智能指針。 一,智能指針分3類:今天只嘮嘮shared_ptr shared_ptr unique_ptr weak_ptr 二,下表是shared_ptr和unique_ptr都支持 ...
智能指針 shared_ptr 使用
上一篇智能指針是啥玩意,介紹了什麼是智能指針。
這一篇簡單說說如何使用智能指針。
一,智能指針分3類:今天只嘮嘮shared_ptr
- shared_ptr
- unique_ptr
- weak_ptr
二,下表是shared_ptr和unique_ptr都支持的操作
操作 | 功能描述 |
---|---|
shared_ptr<T> sp | 空智能指針,可以指向類型為T的對象 |
unique_ptr<T> up | 空智能指針,可以指向類型為T的對象 |
p | 將p用作一個條件判斷,如果p指向一個對象,則為true |
*p | 解引用p,獲得它指向的對象 |
p->mem | 等價於(*p).mem,訪問p所指對象的mem成員 |
p.get() | 返回p中保存的指針。如果指向的對象已經被釋放,就是一個危險的指針 |
swap(p, q)或者p.swap(q) | 交換p和q中的指針 |
上面操作的驗證代碼
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
class Test{
public:
Test(int d = 0):data(d){cout << "cr:" << data << endl;}
~Test(){cout << "fr:" << data << endl;}
void fun(){
cout << "Test func(" << data << ")" << endl;
}
private:
int data;
};
int main(){
//shared_ptr<Test> sp = make_shared<Test>();
Test* pt = new Test();
shared_ptr<Test> sp(pt);
if(sp){
cout << "sp指向了對象" << endl;
}
(*sp).fun();
shared_ptr<int> isp;
if(!isp){
cout << "isp沒有指向對象" << endl;
}
Test* tmp1 = sp.get();
auto sp1 = make_shared<Test>(10);
Test* tmp2 = sp1.get();
swap(sp, sp1);
tmp1->fun();//0
tmp2->fun();//10
//sp和sp1所指向的對象被交換了
sp.get()->fun();//10
sp1.get()->fun();//0
}
三,下表是shared_ptr獨有的操作
操作 | 功能描述 |
---|---|
make_shared<T>(args) | 返回shared_ptr,指向一個動態分配的類型為T的對象。使用args初始化此對象。 |
shared_ptr | p是q的拷貝;遞增q中的計數器。q中的指針必須能轉化成T*。 |
p = q | p和q都是shared_ptr,所保存的指針必須能相互轉換。遞減p的引用計數;遞增q的引用計數;如果p的引用計數變為0,則釋放p管理的對象的記憶體。 |
p.unique() | 如果p.use_count()為1,則返回true;否則返回false |
p.use_count() | 返回與p共用對象的智能指針的數量;性能很低,用於調試。 |
上面操作的驗證代碼
shared_ptr<Test> tsp = make_shared<Test>(11);
cout << tsp.use_count() << endl;//1
//tsp1和tsp指向相同的對象,這個對象的計數器加1
shared_ptr<Test> tsp1(tsp);
cout << tsp.use_count() << endl;//2
//用tsp1改變了對象的data的值,所以用tsp再訪問這個對象,發現對象被改變了
tsp1->setData(111);
tsp->fun();//111
shared_ptr<Test> q(new Test(20));
cout << q.use_count() << endl;//1
cout << tsp.use_count() << endl;//2
//如果q不是智能指針,q指向的Test(20)這塊記憶體就泄露了
//q是智能指針,所以自動釋放了Test(20)這塊記憶體
q = tsp;
cout << q.use_count() << endl;//3
cout << tsp.use_count() << endl;//3
if(!q.unique()){
cout << "不是只有一個智能指針指向了某個對象" << endl;
}
四,智能指針作為函數的返回值
shared_ptr<Test> hun(int d){
return make_shared<Test>(d);
}
void use_hun1(int d){
shared_ptr<Test> p = hun(d);
p->fun();
}//p離開作用域後,它指向的記憶體會被自動釋放
shared_ptr<Test> use_hun2(int d){
shared_ptr<Test> p = hun(d);//計數器為1
return p;//返回p時,計數器遞增,為2
}//離開作用域後,計數器遞減,為1,因為不為0,所以不會釋放
一到四的小例子:
include <memory>
#include <iostream>
#include <vector>
using namespace std;
class Test{
public:
Test(int d = 0):data(d){cout << "cr:" << data << endl;}
~Test(){cout << "fr:" << data << endl;}
void fun(){
cout << "Test func(" << data << ")" << endl;
}
void setData(int d){
data = d;
}
private:
int data;
};
//test3 智能指針作為函數的返回值
shared_ptr<Test> hun(int d){
return make_shared<Test>(d);
}
void use_hun1(int d){
shared_ptr<Test> p = hun(d);
p->fun();
}//p離開作用域後,它指向的記憶體會被自動釋放
shared_ptr<Test> use_hun2(int d){
shared_ptr<Test> p = hun(d);//計數器為1
return p;//返回p時,計數器遞增,為2
}//離開作用域後,計數器遞減,為1,因為不為0,所以不會釋放
int main(){
//test1 shared_ptr和unique_ptr都支持的操作
/*
//shared_ptr<Test> sp = make_shared<Test>();
Test* pt = new Test();
shared_ptr<Test> sp(pt);
if(sp){
cout << "sp指向了對象" << endl;
}
(*sp).fun();
shared_ptr<int> isp;
if(!isp){
cout << "isp沒有指向對象" << endl;
}
Test* tmp1 = sp.get();
auto sp1 = make_shared<Test>(10);
Test* tmp2 = sp1.get();
swap(sp, sp1);
tmp1->fun();
tmp2->fun();
sp.get()->fun();
sp1.get()->fun();
*/
//test2 shared_ptr獨有的操作
/*
shared_ptr<Test> tsp = make_shared<Test>(11);
cout << tsp.use_count() << endl;//1
//tsp1和tsp指向相同的對象,這個對象的計數器加1
shared_ptr<Test> tsp1(tsp);
cout << tsp.use_count() << endl;//2
//用tsp1改變了對象的data的值,所以用tsp再訪問這個對象,發現對象被改變了
tsp1->setData(111);
tsp->fun();//111
shared_ptr<Test> q(new Test(20));
cout << q.use_count() << endl;//1
cout << tsp.use_count() << endl;//2
//如果q不是智能指針,q指向的Test(20)這塊記憶體就泄露了
//q是智能指針,所以自動釋放了Test(20)這塊記憶體
q = tsp;
cout << q.use_count() << endl;//3
cout << tsp.use_count() << endl;//3
if(!q.unique()){
cout << "不是只有一個智能指針指向了某個對象" << endl;
}
*/
//test3 智能指針作為函數的返回值
/*
auto ap = use_hun2(22);
ap->fun();
use_hun1(33);
*/
}
五,智能指針的註意事項
把shared_ptr放入容器中時,之後不再需要全部元素,只使用其中一部分的話,要用erase刪除那些不再需要使用的shared_ptr。如果不erase那些不再需要使用的shared_ptr,shared_ptr就不會釋放它指向的記憶體。
六,智能指針的小例子,讓多個對象共用相同的狀態。
- 有個類shared_vector,裡面有個shared_ptr,指向了一個vector,類shared_vector的對象a2拷貝a1時,實現a1和a2共用vector。
- 類un_shared_vector沒有使用shared_ptr,所以沒有共用vector。
include <iostream>
#include <memory>
#include <vector>
#include <string>
using namespace std;
class shared_vector{
public:
typedef vector<string>::size_type size_type;
shared_vector():data(make_shared<vector<string>>()){}
shared_vector(initializer_list<string> il):
data(make_shared<vector<string>>(il)){}
size_type size()const{return data->size();}
bool empty()const{return data->empty();}
//尾部插入,刪除元素
void push_back(const string& s){data->push_back(s);}
void pop_back(){data->pop_back();}
//訪問元素
string& front(){return data->front();}
string& back(){return data->back();}
private:
shared_ptr<vector<string>> data;
};
class un_shared_vector{
public:
typedef vector<string>::size_type size_type;
un_shared_vector():data(vector<string>()){}
un_shared_vector(initializer_list<string> il):data(il){}
size_type size()const{return data.size();}
bool empty()const{return data.empty();}
//尾部插入,刪除元素
void push_back(const string& s){data.push_back(s);}
void pop_back(){data.pop_back();}
//訪問元素
string& front(){return data.front();}
string& back(){return data.back();}
private:
vector<string> data;
};
int main(){
shared_vector sv{"aa","bb"};
shared_vector sv1(sv);
//因為sv和sv1共用同一個vector,
//所以通過sv改變vector後,通過sv1也發現了相同的改變
sv.push_back("cc");
cout << sv1.back() << endl;
un_shared_vector usv{"11","22"};
un_shared_vector usv1(usv);
//因為usv和usv1不共用同一個vector,
//所以通過usv改變vector後,usv1裡面的vector沒有跟著變化
usv.push_back("33");
cout << usv1.back() << endl;
cout << usv.back() << endl;
}