前言
歡迎來到??小K??的??C++專欄??,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況,這是C和C++程序員的噩夢之一。本節(jié)將為大家?guī)斫鉀Q辦法—>智能指針
1、簡介
?智能指針是一個(gè)模板類,封裝了裸指針,可以對指針進(jìn)行安全的操作。
- 使用RAII特點(diǎn),將對象生命周期使用棧來管理
- 智能指針區(qū)分了所有權(quán),因此使用責(zé)任更為清晰
- 智能指針大量使用操作符重載和函數(shù)內(nèi)聯(lián)特點(diǎn),調(diào)用成本和裸指針無差別
2、為什么要使用智能指針
?一句話:智能指針就是幫我們C++程序員管理動(dòng)態(tài)分配的內(nèi)存的,它會(huì)幫助我們自動(dòng)釋放new出來的內(nèi)存,從而避免內(nèi)存泄漏!
?內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況,這是C和C++程序員的噩夢之一。
3、unique_ptr
?unique_ptr是一種定義在中的智能指針(smart pointer)。它持有對對象的獨(dú)有權(quán)——兩個(gè)unique_ptr不能指向一個(gè)對象,不能進(jìn)行復(fù)制操作只能進(jìn)行移動(dòng)操作。
?unique_ptr對象是管理的對象的唯一擁有者:因?yàn)楫?dāng)unique_ptr對象釋放時(shí)會(huì)刪除它們的托管對象,而不考慮其他指針是否仍然指向相同的對象,從而使指向那里的其他指針指向無效的位置。
?unique_ptr對象復(fù)制了有限的指針功能,通過操作符*和->(用于單個(gè)對象)或操作符[](用于數(shù)組對象)提供對其托管對象的訪問。出于安全考慮,它們不支持指針?biāo)阈g(shù)運(yùn)算,只支持移動(dòng)賦值(禁用復(fù)制賦值)。
?下面是基本的使用方法
void testOne()
{
unique_ptr<int> p(new int(1234));
cout << *p << endl;
unique_ptr<int> p1;
//p1 = p; 錯(cuò)誤,不能賦值和拷貝
//unique_ptr<int> p2(p);
p1 = move(p); //轉(zhuǎn)交所有權(quán)
cout << *p1 << endl;
//cout << *p << endl; //錯(cuò)誤,p已經(jīng)失去了管理對象
unique_ptr<int> p3(new int(897));
p3.reset(p1.release());
cout << *p3 << endl;
}
?需要手動(dòng)寫刪除器的情況,一般是操作自定義類型(且注意unique_ptr
的刪除器寫法的,需要手動(dòng)寫入刪除器類型)
class MM {
public:
~MM() {
cout << "調(diào)用析構(gòu)函數(shù)成功" << endl;
}
};
void testTwo()
{
//unique_ptr刪除器寫法,需要手動(dòng)寫入刪除器類型
unique_ptr<MM,void(*)(MM*&)> Pmm(new MM[4], [](MM*& pmm) {delete[] pmm; });
}
?注意當(dāng)函數(shù)參數(shù)為unique_ptr
類型時(shí),需要使用引用,因?yàn)榇祟愋褪仟?dú)享型,禁止拷貝
void print(unique_ptr<int>& p)
{
cout << *p << endl;
}
4、shared_ptr
?unique_ptr是一個(gè)獨(dú)享指針,同一時(shí)刻只能有一個(gè)unique_ptr指向一個(gè)對象,而shared_ptr是一個(gè)共享指針,同一時(shí)刻可以有多個(gè)shared_ptr指向同一對象,但會(huì)記錄有多少個(gè)shared_ptr共同指向一個(gè)對象。這便是所謂的引用計(jì)數(shù)(reference counting)。
? 一旦最后一個(gè)這樣的指針被銷毀,也就是一旦某個(gè)對象的引用計(jì)數(shù)變?yōu)?,這個(gè)對象會(huì)被自動(dòng)刪除。這在非環(huán)形數(shù)據(jù)結(jié)構(gòu)中防止資源泄露很有幫助。
?基本用法
void testOne()
{
shared_ptr<int> p1; //無參構(gòu)造
if (!p1)
{
cout << "空的智能指針對象" << endl;
}
shared_ptr<int> p2(new int(1234));
//shared_ptr<int> p2 = new int(1234); 錯(cuò)誤
shared_ptr<int> p3 = make_shared<int>(1234); //使用make_shared不支持創(chuàng)建數(shù)組
//怎么訪問數(shù)據(jù),直接把智能指針對象當(dāng)做指針來用
cout << *p3 << endl;
//cout << p3[0] << endl; 錯(cuò)誤,沒有下標(biāo)的使用方式
//獲取管理對象原生指針
int* k = p3.get();
cout << *k << endl;
cout << k[0] << endl;
//注意:千萬不要手動(dòng)釋放原生指針,否則會(huì)中斷(釋放兩次)
//delete k;
cout << "管理對象數(shù):" << p3.use_count() << endl;
shared_ptr<int> p4(p3);
cout << "管理對象數(shù):" << p3.use_count() << endl;
}
?vector管理普通指針的弊端
class MM
{
public:
MM(string name="",int age=0):name(name),age(age){}
void print()
{
cout << name << "\t" << age << endl;
}
~MM()
{
cout << "調(diào)用析構(gòu)函數(shù)" << endl;
}
protected:
string name;
int age;
};
void testTwo()
{
cout <<"-----------------------------------" << endl;
shared_ptr<MM> p(new MM("name1", 19));
p->print();
/*****************vector弊端*****************/
vector<MM*> p1;
p1.push_back(new MM("name", 20));
//p1.pop_back();
p1.clear();
//可以看到pop和clear函數(shù)都不會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)---->當(dāng)vector操作自定義類型指針的時(shí)候
/*******************************************/
//比較常用的用法--->工作中
vector<shared_ptr<MM>> arr;
shared_ptr<MM> p2(new MM("name"));
p2->print();
arr.push_back(p2);
}
上面代碼中,當(dāng)vector管理MM*
類型的時(shí)候,并不會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),這時(shí)候我們只需要讓vector管理shared_ptr
就好了
?需要手動(dòng)寫刪除器的情況,和unique_ptr
一樣
void testThree()
{
cout << "-----------------------------------" << endl;
shared_ptr<int> king(new int[4] {1, 2, 3, 4});
int* pNum = king.get();
for (int i = 0; i < 4; i++)
{
cout << pNum[i] << " ";
}
cout << endl;
//當(dāng)操作特殊類型(自定義類型,c語言文件的打開)的時(shí)候,需要手動(dòng)寫刪除器
shared_ptr<MM> p1(new MM[4], [](MM*& pmm) {delete[]pmm; });
shared_ptr<FILE> pfile(fopen("1.txt", "w+"), [](FILE*& file) {free(file); });
}
?當(dāng)shared_ptr
當(dāng)函數(shù)參數(shù)和返回值的時(shí)候,正常寫就ok
void pprint(shared_ptr<MM>& mm) {
mm->print();
}
shared_ptr<int> returnpoint(int num) {
return shared_ptr<int>(new int(num));
}
5、weak_ptr
?shared_ptr可以用來避免內(nèi)存泄漏,可以自動(dòng)釋放內(nèi)存。但是在使用中可能存在循環(huán)引用,使引用計(jì)數(shù)失效,從而導(dǎo)致內(nèi)存泄漏的情況。如下代碼所示:
class B;
class A {
public:
~A() {
cout << "A" << endl;
}
shared_ptr<B> a;
};
class B {
public:
~B() {
cout << "B" << endl;
}
shared_ptr<A> b;
};
void testOne()
{
shared_ptr<A> ao(new A);
shared_ptr<B> bo(new B);
ao->a = bo;
bo->b = ao;
}
我們發(fā)現(xiàn)上面的一段代碼中,ao中的指針管理bo,bo中的指針管理ao,形成了循環(huán)管理,這時(shí)候就不會(huì)自動(dòng)釋放。這時(shí)候我們只需要把shared_ptr
改為weak_ptr
就ok了
?基本處理文章來源:http://www.zghlxwxcb.cn/news/detail-457596.html
weak_ptr只能從shared_ptr或者已有的weak_ptr去構(gòu)造,不能直接管理對象
不能直接訪問管理的對象,訪問數(shù)據(jù)要通過lock()函數(shù)去訪問shared_ptr,然后再去訪問數(shù)據(jù)文章來源地址http://www.zghlxwxcb.cn/news/detail-457596.html
void testTwo()
{
shared_ptr<int> p(new int(1234));
cout << "count:" << p.use_count() << endl;
weak_ptr<int> w(p);
cout << "count:" << w.use_count() << endl;
weak_ptr<int> w2(w);
cout << "count:" << w2.use_count() << endl;
cout << *w.lock() << endl;
shared_ptr<int> k = w2.lock();
cout << *k << endl;
}
到了這里,關(guān)于智能指針:C++中優(yōu)雅的內(nèi)存管理解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!