c++智能指针 unique_ptr 独占指针unique_ptr· unique_ptr在任何给定的时刻只能有一个指针管理内存· 当指针超出作用域时内存将自动释放· 该类型指针不可copy只可以move三种创建方式· 通过已有裸指针创建(通过该方式创建建议将裸指针设为空且销毁掉否则不能满足独占的需求)Class*c_p1newClass();std::unique_ptrClassu_c_p1(c_p1);此时 c_p1 可以继续使用coutc_p1-getInfo()endl coutu_c_p1-getInfo()endl;c_p1-setInfo(new value);coutu_c_p2-getInfo()endl;通过c_p1的set函数设置成员变量的值发现u_c_p1中的值也随之变化。说明目前二者共用c_p1内存的数据。建议在设置完unique_ptr之后销毁掉c_p1deletec_p1;c_p1nullptr;· 通过new来创建和第一种没什么区别std::unique_ptrClassu_c_p1(newClass());coutu_c_p1-getInfo()endl;u_c_p1-setInfo(new value);coutu_c_p1-getInfo()endl;结果可以看到setInfo函数下的打印结果为new value· 通过std::make_unique来创建推荐不需要指向空std::unique_ptrClassu_c_p1make_uniqueClass();coutu_c_p1-getInfo()endl;u_c_p1-setInfo(new value);coutu_c_p1-getInfo()endl;结果可以看到setInfo函数下的打印结果为new value代码实践使用vs创建如下项目变量在堆和栈中的销毁方式自定义类该类主要目的为直观体现析构函数是否被调用和实现功能函数CustomClass.h#pragmaonce#includestring#includeiostream// 自定义类classCustomClass{public:CustomClass(std::string name);CustomClass()default;~CustomClass();// -voidcat_info()const{std::coutcat_info name namestd::endl;}std::stringget_name()const{returnname;}voidset_name(conststd::stringname){this-namename;}private:std::string name{Default Name};};CustomClass.cpp#includeCustomClass.hCustomClass::CustomClass(std::string name):name(name){std::coutConstructor of CustomClass : namestd::endl;}CustomClass::~CustomClass(){std::coutDestructor of CustomClass : namestd::endl;}在堆上的变量#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// stack// 在栈上的指针会自动销毁CustomClassc1(Out {});c1.cat_info();{CustomClassc1(In {});c1.cat_info();}std::cout----------- END --------------------\n;return0;}打印结果· 在栈上创建的变量会自动销毁作用域结束后就自动销毁掉了· 可以看到{}内的变量在代码运行到{}结束后析构函数内的打印出现说明该变量就被销毁掉了· main函数内的变量会在main函数运行后才会进行销毁所以可以看到{}外的c1变量析构打印在main函数的END之后在栈上的变量#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 裸指针原始指针 row pointer// 指向堆需要手动释放CustomClass*pC1newCustomClass(pointer 1 OUT{});pC1-cat_info();{CustomClass*pC1newCustomClass(pointer 1 IN{});pC1-cat_info();}std::cout----------- END --------------------\n;return0;}打印结果在堆上的变量是需要手动进行销毁的可以看到此时没有手动销毁变量没有析构函数的打印#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 裸指针原始指针 row pointer// 指向堆需要手动释放CustomClass*pC1newCustomClass(pointer 1 OUT{});pC1-cat_info();{CustomClass*pC1newCustomClass(pointer 1 IN{});pC1-cat_info();deletepC1;}deletepC1;std::cout----------- END --------------------\n;return0;}打印结果手动调用delete后可以看到析构函数的打印出现变量被销毁unique_ptr创建的三种方式1、使用原始指针#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 裸指针CustomClass*pc1newCustomClass(row pointer);std::unique_ptrCustomClassupc1{pc1};pc1-cat_info();upc1-cat_info();pc1-set_name(change row pointer);upc1-cat_info();std::cout----------- END --------------------\n;return0;}打印结果可以看到当原始指针改变数值时unique指针也改变了对应的数值而且原始指针只是被unique_ptr指向并没有自动销毁仍需手动销毁指针由此得到通过c_p1的set函数设置成员变量的值发现u_c_p1中的值也随之变化。说明目前二者共用c_p1内存的数据。建议在设置完unique_ptr之后销毁掉裸指针的推荐写法#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 裸指针 推荐写法CustomClass*pc1newCustomClass(row pointer);std::unique_ptrCustomClassupc1{pc1};pc1nullptr;// 注意 这里一定要先置空再delete不然后续unique_ptr使用时会崩溃deletepc1;upc1-cat_info();std::cout----------- END --------------------\n;return0;}2、 new#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 第二种 new的方式创建std::unique_ptrCustomClassupc1{newCustomClass(new point)};upc1-cat_info();upc1-set_name(change new point);upc1-cat_info();std::cout----------- END --------------------\n;return0;}打印结果3、make_uniqueC推荐写法#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// 第三种 使用std::make_unique 推荐使用std::unique_ptrCustomClassupc1make_uniqueCustomClass();upc1-cat_info();upc1-set_name(change make default point);upc1-cat_info();std::unique_ptrCustomClassupc2make_uniqueCustomClass(make point);upc2-cat_info();upc2-set_name(change make point);upc2-cat_info();std::cout----------- END --------------------\n;return0;}打印结果get 和 常量类型#includeiostream// 智能指针头文件#includememory// 自定义类头文件#includeCustomClass.husingnamespacestd;intmain(){// get 和 常量类型std::unique_ptrCustomClassupc1make_uniqueCustomClass();std::unique_ptrintupi1make_uniqueint(100);upc1-cat_info();upc1-set_name(change make default point);upc1-cat_info();// 解引用std::cout*upi1std::endl;// 地址std::coutint address: upi1.get()std::endl;std::coutCustomClass address: upc1.get()std::endl;std::unique_ptrCustomClassupc2make_uniqueCustomClass(make point);upc2-cat_info();upc2-set_name(change make point);upc2-cat_info();std::cout----------- END --------------------\n;return0;}打印结果总结1、unique_ptr属于独占指针推荐使用 make_unique 函数进行构建2、unique_ptr在代码超出作用域后会自动释放3、若使用 new 方法对unique_ptr进行赋值依旧需要手动释放原指针违背了智能指针自动回收避免内存泄漏的初衷