智能指針是一個(gè)類,用來(lái)存儲(chǔ)指向動(dòng)態(tài)分配對(duì)象的指針,負(fù)責(zé)自動(dòng)釋放動(dòng)態(tài)分配的對(duì)象吊圾,防止內(nèi)存泄漏。動(dòng)態(tài)分配的資源交給一個(gè)類對(duì)象去管理翰蠢,當(dāng)類對(duì)象聲明周期結(jié)束時(shí)项乒,自動(dòng)調(diào)用析構(gòu)函數(shù)釋放資源。
shared_ptr
采用引用計(jì)數(shù)器的方法梁沧,允許多個(gè)智能指針指向同一個(gè)對(duì)象檀何,每當(dāng)多一個(gè)指針指向該對(duì)象時(shí),指向該對(duì)象的所有智能指針內(nèi)部的引用計(jì)數(shù)加1廷支,每當(dāng)減少一個(gè)智能指針指向?qū)ο髸r(shí)频鉴,引用計(jì)數(shù)減1,當(dāng)計(jì)數(shù)為0時(shí)自動(dòng)釋放動(dòng)態(tài)分配的資源恋拍。
#include <memory>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
string str = "hello world";
shared_ptr<string> p1(new string(str));
shared_ptr<string> p2(p1);
shared_ptr<string> p3 = p1; //允許多個(gè)指針指向同一個(gè)對(duì)象
cout << *p1 << endl;
cout << *p2 << endl;
cout << *p3 << endl;
shared_ptr<string> ps1;
//從普通指針構(gòu)造智能指針
string* str1 = new string("xian");
//ps1 = str1; //隱式轉(zhuǎn)換不可以
ps1 = shared_ptr<string>(str1); //顯示轉(zhuǎn)換可以
//shared_ptr<string> ps2 = str1; //隱式轉(zhuǎn)換不可以
//shared_ptr<string> ps3(str1); //顯式轉(zhuǎn)換(出現(xiàn)程序崩潰垛孔,因?yàn)槎鄠€(gè)智能指針指向了同一塊內(nèi)存,會(huì)引起重復(fù)釋放內(nèi)存的問題),
shared_ptr<string> ps3(ps1); //多個(gè)智能指針指向同一塊內(nèi)存芝囤,但是使用智能指針是采用引用計(jì)數(shù)的原理似炎,只有當(dāng)引用計(jì)數(shù)為0時(shí)辛萍,才delete這塊內(nèi)存
cout << *ps1 << endl;
cout << *ps3 << endl;
return 0;
}
auto_ptr
主要是為了解決“有異常拋出時(shí)發(fā)生內(nèi)存泄漏”的問題悯姊。因?yàn)榘l(fā)生異常而無(wú)法正常釋放內(nèi)存。auto_ptr有拷貝語(yǔ)義贩毕,拷貝后源對(duì)象變得無(wú)效悯许,程序崩潰,而unique_ptr沒有拷貝語(yǔ)義辉阶,提供了移動(dòng)語(yǔ)義(使用std::move)進(jìn)行轉(zhuǎn)移先壕。所以unique_ptr比auto_ptr更安全瘩扼。
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
string* str1 = new string("hello ");
auto_ptr<string> p1(str1);
auto_ptr<string> p2(p1); //自動(dòng)將p1的所有權(quán)剝奪,導(dǎo)致p1無(wú)法訪問垃僚,不夠安全集绰,建議使用unique_ptr
//cout << *p1 << endl;
cout << *p2 << endl;
return 0;
}
unique_ptr
采用獨(dú)享所有權(quán)定義,一個(gè)非空的unique_ptr總是擁有它所指向的資源谆棺,轉(zhuǎn)移一個(gè)unique_ptr會(huì)把所有權(quán)全部從源指針轉(zhuǎn)移給目標(biāo)指針栽燕,源指針被置空;所以unique_ptr不支持普通的拷貝和賦值操作改淑。
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
string* str1 = new string("hello ");
unique_ptr<string> p1(str1);
//unique_ptr<string> p2 = p1; //不允許這樣做
unique_ptr<string> p2 = move(p1);
//cout << *p1 << endl; //p1已經(jīng)喪失了所有權(quán)
cout << *p2 << endl;
return 0;
}
weak_ptr
弱引用碍岔。引用計(jì)數(shù)有一個(gè)問題就是互相引用形成環(huán)(環(huán)形引用),這樣兩個(gè)指針指向的內(nèi)存都無(wú)法釋放朵夏。需要使用weak_ptr打破環(huán)形應(yīng)用蔼啦,是為了配合shared_ptr而引入的一種智能指針,它指向一個(gè)由shared_ptr管理的對(duì)象而不影響所指對(duì)象的生命周期仰猖,也就是說(shuō)它只引用捏肢,不計(jì)數(shù)。
#include <iostream>
using namespace std;
class A;
class B;
class A
{
public:
//shared_ptr<B> b_ptr;
weak_ptr<B> b_ptr; //修改為若應(yīng)用即可解決循環(huán)引用的問題
};
class B
{
public:
//shared_ptr<A> a_ptr;
weak_ptr<A> a_ptr; //修改為若應(yīng)用即可解決循環(huán)引用的問題
};
int main(int argc, char** argv)
{
string* str1 = new string("hell0");
shared_ptr<string> p(str1);
//weak_ptr<string> p1(str1); //出錯(cuò)
weak_ptr<string> p1(p); //可以指向已有的shared_ptr
//cout << *p1 << endl; //不支持*操作
cout << p1.use_count() << endl; //查看與自己指向同一個(gè)對(duì)象的shared_ptr的引用計(jì)數(shù)饥侵,但是自己只引用不會(huì)增加或減少計(jì)數(shù)
shared_ptr<string> p2 = p1.lock();
cout << *p2 << endl; //借助lock函數(shù)返回一個(gè)和p1指向同一個(gè)對(duì)象的shared_ptr類型指針猛计,獲取其存儲(chǔ)的數(shù)據(jù)。
cout << p1.use_count() << endl;
//**************循環(huán)引用******************
shared_ptr<A> pa(new A);
shared_ptr<B> pb(new B);
pa->b_ptr = pb;
pb->a_ptr = pa;
//如果不是弱引用爆捞,兩個(gè)的引用計(jì)數(shù)都為2奉瘤,這個(gè)情況下最后的引用計(jì)數(shù)不為2,造成兩個(gè)內(nèi)存得不到釋放煮甥,導(dǎo)致內(nèi)存泄漏
cout << "pa.use_count=" << pa.use_count() << endl;
cout << "pb.use_count=" << pb.use_count() << endl;
return 0;
}