C++內存管理之unique_ptr


 

  一個unique_ptr"擁有“他所指向的對象。與shared_ptr不同,某個時刻只能有一個unique_ptr指向一個給定的對象。當unique_ptr被銷毀時,它所指向的對象也被銷毀。uniptr_ptr表達的是一種獨占的思想。

 

初始化

#include <iostream> #include <memory> using namespace std; //常規操作 int main(int argc, char *argv[]) { unique_ptr<double> p1; //!可指向一個double的unique_ptr unique_ptr<int> p2(new int(56)); //!p2指向了一個值為42的int  unique_ptr<string> pstr(new string("strtest")); // unique_ptr<string> pstrCopy(pstr); //!error: 不支持對象的拷貝 unique_ptr<string> pstrAssin; // pstrAssin = pstr //!error: uniptr不支持賦值 return 0; }

 

unique_ptr一般操作

 

  關於unique_ptr還支持哪些操作,在前面的博文中我也做了總結,請參考該篇文章中圖表:https://www.cnblogs.com/wangkeqin/p/9351191.html

 

 

 unique_ptr所有權轉移

  雖然我們不能拷貝賦值unique_ptr,但是可以通過調用release或者set將指針的所有權從一個(非const)unique_ptr轉移給一個unique:

#include <iostream> #include <memory> using namespace std; class TEST { public: TEST(const string & name) :_name(name) {cout<<"TEST:"<<_name<<endl;} TEST(const TEST & another) { _name = another._name; cout<<another._name<<" copyStruct "<<_name<<endl;} TEST & operator =(const TEST & another){ if(&another==this) return *this; this->_name=another._name; cout<<another._name<<" copyAssin to "<<_name<<endl; } ~TEST(){cout<<"~TEST:"<<_name<<endl;} //private: string _name; }; //其他操作 int main() { unique_ptr<TEST> p1(new TEST("case_1")); unique_ptr<TEST> p2(p1.release()); //!將所有權從p1轉移到p2,p1現在指向NULL。 cout<<"++++++++++++++++++++++++"<<endl; unique_ptr<TEST> p3(new TEST("case_2")); p2.reset(p3.release()); //!p2釋放了原來指向的內存,接受了p3指向的內存。  getchar(); }

 

 

傳遞unique_ptr參數和返回unique_ptr

  不能拷貝unique_ptr的規則有一個例外:我們可以拷貝或者賦值一個將要被銷毀的unique_ptr。其本質就是調用了移動拷貝和移動賦值;最常見的例子是從函數返回一個unique_ptr:

#include <iostream> #include <memory> using namespace std; class TEST { public: TEST(const string & name) :_name(name) {cout<<"TEST:"<<_name<<endl;} TEST(const TEST & another) { _name = another._name; cout<<another._name<<" copyStruct "<<_name<<endl;} TEST & operator =(const TEST & another){ if(&another==this) return *this; this->_name=another._name; cout<<another._name<<" copyAssin to "<<_name<<endl; } ~TEST(){cout<<"~TEST:"<<_name<<endl;} //private: string _name; }; //!例外: //①返回一個即將被銷毀的uniptr unique_ptr<TEST> retDying(string param) { return unique_ptr<TEST>(new TEST(param)); } //②返回一個局部對象; unique_ptr<TEST> retTemp(string param) { unique_ptr<TEST> pTemp(new TEST(param)); return pTemp; } int main() { unique_ptr<TEST>ret1 = retDying("dying"); cout<<(*ret1)._name<<endl; unique_ptr<TEST>ret2 = retTemp("temp"); cout<<(*ret2)._name<<endl; getchar(); }

 

 

向后兼容:auto_ptr

  標准庫較早的版本包含了一個名為auto_ptr的類,它具有unique_ptr的部分特性,但不是全部。特別時我們在容器中保存auto_ptr,也不能從函數中返回auto_ptr。雖然auto_ptr仍然是標准庫的一部分,但是編寫程序時應該使用unique_ptr。

 

向unique_ptr傳遞刪除器

  類似於shared_ptr,unique_ptr默認情況下也是使用delete釋放它指向的對象。與shared_ptr一樣,我們可以重載一個unique_ptr中默認的刪除器。但是unique_ptr管理刪除器的方式與shared_ptr不同,其原因我們將在后面繼續補充。

  重載一個unique_ptr中的刪除器會影響到unique_ptr類型如何構造(或reset)該類型的對象。與重載關聯器的比較操作類似。我們必須在尖括號中unique_ptr指向類型之后提供刪除器類型。在創建或者reset一個這種unique_ptr這種類型的對象時,必須提供一個指定類型的可調用對象:

 

#include <stdio.h> #include <memory> using namespace std; void closePf(FILE * pf) { cout<<"----close pf after works!----"<<endl; fclose(pf); cout<<"*****end working****"<<endl; } int main() { // FILE * fp2 = fopen("bin2.txt", "w"); // if(!pf) // return -1; // char *buf = "abcdefg"; // fwrite(buf, 8, 1, fp2); // fclose(fp2); //______________________________________ // shared_ptr<FILE> pf(fopen("bin2.txt", "w"),closePf); // cout<<"*****start working****"<<endl; // if(!pf) // return -1; // char *buf = "abcdefg"; // fwrite(buf, 8, 1, pf.get()); //!確保fwrite不會刪除指針的情況下,可以將shared_ptr內置指針取出來。 // cout<<"----write int file!-----"<<endl;  unique_ptr<FILE,decltype(closePf)*> pf(fopen("bin2.txt", "w"),closePf); //!使用了decltype類型推斷 cout<<"*****start working****"<<endl; if(!pf) return -1; char *buf = "abcdefg"; fwrite(buf, 8, 1, pf.get());                         //!確保fwrite不會刪除指針的情況下,可以將unique_ptr內置指針取出來。 cout<<"----write int file!-----"<<endl; return 0; }

 

使用unique_ptr管理動態數組

  標准庫提供了一個可以管理new分配動態數組的unique_ptr版本。為了用用一個unique_ptr管理動態數組,我們必須在對象類型后面跟一對空方括號;如此,在unique對象銷毀的時候,也可以自動調用delete[ ]而非delete來完成內存的釋放。

#include <iostream> #include <memory> using namespace std; class ArrTest { public: ArrTest(){ static int i = 0; _i = i; cout<<" ArrTest()"<<":"<<i++<<endl; } ~ArrTest(){ static int i = 0; cout<<"~ ArrTest()"<<":"<<i++<<endl; } int _i; }; int main() { unique_ptr<ArrTest[]> p(new ArrTest[10]); cout<<p[4]._i<<endl; //!獲取某個元素值,警告:不要使用越界的下標,unique_ptr也是不檢查越界的。  p.reset(); return 0; }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM