C++智能指針的使用
智能指針的使用場(chǎng)景
1. 下面的程序中,new了以后,我們也delete了,但是因?yàn)閽伄惓?dǎo)致后面的delete沒(méi)有得到執(zhí)行,所以就內(nèi)存泄漏了,所以我們需要new以后捕獲異常,捕獲到異常后delete內(nèi)存,再把異常拋出。
2.但是因?yàn)閚ew本身也可能拋異常,連續(xù)的兩個(gè)new和下面的Divide都可能會(huì)拋異常,讓我們處理起來(lái)很麻煩。智能指針?lè)诺竭@樣的場(chǎng)景里面就讓問(wèn)題簡(jiǎn)單多了。
double Divide(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
{
throw "Divide by zero condition!";
}
else
{
return (double)a / (double)b;
}
}
void Func()
{
// 這?可以看到如果發(fā)?除0錯(cuò)誤拋出異常,另外下?的array和array2沒(méi)有得到釋放。
// 所以這?捕獲異常后并不處理異常,異常還是交給外?處理,這?捕獲了再重新拋出去。
// 但是如果array2new的時(shí)候拋異常呢,就還需要套?層捕獲釋放邏輯,這?更好解決?案
// 是智能指針,否則代碼太戳了
int* array1 = new int[10];
int* array2 = new int[10];// 拋異常呢
// 連續(xù)的兩個(gè)new
// 如果第一個(gè)new拋異??梢圆东@
// 如果第二個(gè)new拋異常,可以解決delete第二個(gè)new
// 但是第一個(gè)new沒(méi)有被delete
// 這樣就需要再第二個(gè)new的地方捕獲異常,delete第一個(gè)new
// 如果有很多個(gè)new呢,就太麻煩了,這里就需要智能指針了
try
{
int len, time;
cin >> len >> time;
cout << Divide(len, time) << endl;
}
catch (...)
{
cout << "delete []" << array1 << endl;
cout << "delete []" << array2 << endl;
delete[] array1;
delete[] array2;
throw; // 異常重新拋出,捕獲到什么拋出什么
}
// ...
cout << "delete []" << array1 << endl;
delete[] array1;
cout << "delete []" << array2 << endl;
delete[] array2;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
catch (...)
{
cout << "未知異常" << endl;
}
return 0;
}
RAII和智能指針
1. RAII是獲取到資源立即初始化,它是一種管理資源的類的設(shè)計(jì)思想,本質(zhì)是一種利用對(duì)象生命周期來(lái)管理獲取到的動(dòng)態(tài)資源,避免資源泄漏,這里的資源可以是內(nèi)存、文件指針、網(wǎng)絡(luò)連接、互斥鎖等等。RAII在獲取資源時(shí)把資源委托給一個(gè)對(duì)象,接著控制對(duì)資源的訪問(wèn),資源在對(duì)象的生命周期內(nèi)始終保持有效,最后在對(duì)象析構(gòu)的時(shí)候釋放資源,這樣保障了資源的正常釋放,避免資源泄漏問(wèn)題。
2. RAII像指針一樣
在對(duì)象銷毀后會(huì)正常的釋放資源
template<class T>
class SmartPtr
{
public:
// RAII
SmartPtr(T* ptr)
:_ptr(ptr)
{}
~SmartPtr()
{
cout << "delete[] " << _ptr << endl;
delete[] _ptr;
}
private:
T* _ptr;
};
double Divide(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
{
throw "Divide by zero condition!";
}
else
{
return (double)a / (double)b;
}
}
void Func()
{
// 這?可以看到如果發(fā)?除0錯(cuò)誤拋出異常,另外下?的array和array2沒(méi)有得到釋放。
// 所以這?捕獲異常后并不處理異常,異常還是交給外?處理,這?捕獲了再重新拋出去。
// 但是如果array2new的時(shí)候拋異常呢,就還需要套?層捕獲釋放邏輯,這?更好解決?案
// 是智能指針,否則代碼太戳了
SmartPtr<int> p1 = new int[10];
SmartPtr<int> p2 = new int[10];// 拋異常呢
SmartPtr<int> p3 = new int[10];
int len, time;
cin >> len >> time;
cout << Divide(len, time) << endl;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
catch (...)
{
cout << "未知異常" << endl;
}
return 0;
}
智能指針類除了滿足RAII的設(shè)計(jì)思路,還要方便資源的訪問(wèn),所以智能指針類還像迭代器類一樣重載 operator*/operator->/operator[] 等運(yùn)算符,方便訪問(wèn)資源。
template<class T>
class SmartPtr
{
public:
// RAII
SmartPtr(T* ptr)
:_ptr(ptr)
{}
~SmartPtr()
{
cout << "delete[] " << _ptr << endl;
delete[] _ptr;
}
// 重載運(yùn)算符,模擬指針的?為,?便訪問(wèn)資源
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T& operator[](size_t i)
{
return _ptr[i];
}
private:
T* _ptr;
};
void Func()
{
p1[1] = 50;
p4->first = 1;
p4->second = 2;
cout << p1[1] << endl;
}
C++標(biāo)準(zhǔn)庫(kù)智能指針的使用
淺拷貝的問(wèn)題,共同管理同一塊資源,而深拷貝是兩個(gè)指針管理不同的資源了,現(xiàn)在要求兩個(gè)指針管理同一塊資源?
int main()
{
// 需要p1和p2同時(shí)管理同一塊資源,淺拷貝
// 析構(gòu)多次的問(wèn)題如何解決?
SmartPtr<int> p1 = new int[10];
SmartPtr<int> p2(p1);
return 0;
}
1.C++標(biāo)準(zhǔn)庫(kù)中的智能指針都在< memory >這個(gè)頭文件下,智能指針有好幾種,除了weak_ptr他們都符合RAII和像指針一樣訪問(wèn)的行為,原理上而言主要是解決智能指針拷貝時(shí)的思路不同。
2. C++98的智能指針
auto_ptr是C++98時(shí)設(shè)計(jì)出來(lái)的智能指針,它的特點(diǎn)是拷貝時(shí)把被拷貝對(duì)象的資源的管理權(quán)轉(zhuǎn)移給拷貝對(duì)象,這是?個(gè)非常糟糕的設(shè)計(jì),因?yàn)樗麜?huì)把被拷貝對(duì)象懸空(相當(dāng)于被拷貝對(duì)象是空指針了),訪問(wèn)報(bào)錯(cuò)的問(wèn)題,C++11設(shè)計(jì)出新的智能指針后,強(qiáng)烈建議不要使用auto_ptr
struct Date
{
int _year;
int _month;
int _day;
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
// 本身不需要析構(gòu),為了驗(yàn)證auto_ptr是否可以解決析構(gòu)兩次的問(wèn)題
~Date()
{
cout << "~Date()" << endl;
}
};
int main()
{
// 拷?時(shí),管理權(quán)限轉(zhuǎn)移,被拷?對(duì)象ap1懸空
auto_ptr<Date> ap1(new Date);
auto_ptr<Date> ap2(ap1);
// 空指針訪問(wèn),ap1對(duì)象已經(jīng)懸空
// ap1->_year++;
return 0;
}
C++11的智能指針
2、unique_ptr是唯一指針,他的特點(diǎn)是不支持拷貝,只支持移動(dòng)。如果不需要拷貝的場(chǎng)景就非常建議使用它。把拷貝構(gòu)造和拷貝賦值給(封)delete了
int main()
{
unique_ptr<Date> up1(new Date);
不支持拷貝
// unique_ptr<Date> up2(up1);
支持移動(dòng),移動(dòng)后up1也懸空了
unique_ptr<Date> up3(move(up1));
return 0;
}
3、shared_ptr共享指針,他的特點(diǎn)是支持拷貝,也支持移動(dòng)。如果需要拷貝的場(chǎng)景就需要使用他了。底層是用引用計(jì)數(shù)的方式實(shí)現(xiàn)的。
int main()
{
shared_ptr<Date> p1(new Date);
shared_ptr<Date> p2(p1);
shared_ptr<Date> p3(p1);
cout << p1.use_count() << endl;// 3
p1->_day++;
cout << p1->_day << endl; // 2
cout << p2->_day << endl; // 2
cout << p3->_day << endl; // 2
return 0;
}
4、weak_ptr弱(輔助解決shared_ptr的一個(gè)問(wèn)題)指針,它不同于上面的指針,它不支持RAII,也就意味著不能用它直接管理資源,weak_ptr的產(chǎn)生本質(zhì)是要解決shared_ptr的一個(gè)循環(huán)引用導(dǎo)致內(nèi)存泄漏的問(wèn)題。
到此這篇關(guān)于C++智能指針的使用的文章就介紹到這了,更多相關(guān)C++智能指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)考試報(bào)名管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)考試報(bào)名管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
C++類的自動(dòng)轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換的實(shí)現(xiàn)示例
類的自動(dòng)轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換是面向?qū)ο缶幊讨刑幚眍愋椭g轉(zhuǎn)換的兩種重要機(jī)制,本文就來(lái)介紹一下這兩種方法的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07
解析C++編程中異常相關(guān)的堆棧展開(kāi)和throw()異常規(guī)范
這篇文章主要介紹了C++編程中異常相關(guān)的堆棧展開(kāi)和throw()異常規(guī)范,throw()規(guī)范部分文中結(jié)合了C++11標(biāo)準(zhǔn)的新特性來(lái)講,需要的朋友可以參考下2016-01-01
VC List Control控件如何刪除選中的記錄實(shí)例詳解
這篇文章主要介紹了VC List Control控件如何刪除選中的記錄實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06
C++實(shí)現(xiàn)LeetCode(92.倒置鏈表之二)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(倒置鏈表之二),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
基于OpenCV實(shí)現(xiàn)車道線檢測(cè)(自動(dòng)駕駛 機(jī)器視覺(jué))
無(wú)人駕駛技術(shù)是機(jī)器學(xué)習(xí)為主的一門前沿領(lǐng)域,在無(wú)人駕駛領(lǐng)域中機(jī)器學(xué)習(xí)的各種算法隨處可見(jiàn),本文將為大家介紹無(wú)人駕駛技術(shù)中的車道線檢測(cè),感興趣的小伙伴可以了解一下2021-11-11
OpenCV實(shí)現(xiàn)簡(jiǎn)單錄屏功能
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)簡(jiǎn)單錄屏功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01

