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