unique_ptr使用场景
1、为动态申请的资源提供异常安全保证
我们先来看看下面这一段代码:
void Func() { int *p = new int(5); // ...(可能会抛出异常) delete p; }
这是我们传统的写法:当我们动态申请内存后,有可能我们接下来的代码由于抛出异常或者提前退出(if语句)而没有执行delete操作。
解决的方法是使用unique_ptr来管理动态内存,只要unique_ptr指针创建成功,其析构函数都会被调用。确保动态资源被释放。
void Func() { unique_ptr<int> p(new int(5)); // ...(可能会抛出异常) }
2、返回函数内动态申请资源的所有权
unique_ptr<int> Func(int p) { unique_ptr<int> pInt(new int(p)); return pInt; // 返回unique_ptr } int main() { int p = 5; unique_ptr<int> ret = Func(p); cout << *ret << endl; // 函数结束后,自动释放资源 }
3、在容器中保存指针
int main() { vector<unique_ptr<int>> vec; unique_ptr<int> p(new int(5)); vec.push_back(std::move(p)); // 使用移动语义 }
4、管理动态数组
标准库提供了一个可以管理动态数组的unique_ptr版本。
int main() { unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5}); p[0] = 0; // 重载了operator[] }
5、作为auto_ptr的替代品
创建与释放举例
#include <iostream> #include <memory> #include <stdlib.h> struct Foo { Foo() { std::cout << "Foo::Foo\n"; } ~Foo() { std::cout << "Foo::~Foo\n"; } void bar() { std::cout << "Foo::bar\n"; } }; void f(const Foo &) { std::cout << "f(const Foo&)\n"; } struct D { void operator()(Foo* foo) { std::cout << "D operator()" << std::endl; delete foo; } }; void TestAutoDestroy() { //1. 普通的new对象. std::cout << "TestDestroy...................." << std::endl; { std::unique_ptr<Foo> p1(new Foo); } //2. 普通的new[]对象. { std::unique_ptr<Foo[]> p2(new Foo[4]); } //3. 自定义的deleter. { std::unique_ptr<Foo, D> p3(new Foo); } } void TestOwner() { std::cout << "TestOwner...................." << std::endl; //1. new object. std::unique_ptr<Foo> p1(new Foo); // p1 owns Foo if (p1) p1->bar(); { std::unique_ptr<Foo> p2(std::move(p1)); // now p2 owns Foo f(*p2); p1 = std::move(p2); // ownership returns to p1 p2->bar(); std::cout << "destroying p2...\n"; } p1->bar(); } void TestArrayOwner() { std::cout << "TestArrayOwner...................." << std::endl; //1. new[] object. std::unique_ptr<Foo[]> p1(new Foo[4]); // p1 owns Foo if (p1) p1[0].bar(); { std::unique_ptr<Foo[]> p2(std::move(p1)); // now p2 owns Foo f(p2[0]); p1 = std::move(p2); // ownership returns to p1 p2[0].bar(); std::cout << "destroying p2...\n"; } p1[0].bar(); } int main() { TestAutoDestroy(); TestOwner(); TestArrayOwner(); }
输出:
TestDestroy.................... Foo::Foo Foo::~Foo Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::Foo D operator() Foo::~Foo TestOwner.................... Foo::Foo Foo::bar f(const Foo&) Foo::bar destroying p2... Foo::bar Foo::~Foo TestArrayOwner.................... Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::bar f(const Foo&) Foo::bar destroying p2... Foo::bar Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo
part 2
uniqut_ptr是一种对资源具有排他性拥有权的智能指针,即一个对象资源只能同时被一个unique_ptr指向。
一、初始化方式
通过new云算法或者普通指针
unique_ptr<Investment> up(new Investment());
或者
Investment *pInv = new Investment();
unique_ptr<Investment> up1(pInv);
通过make_unique
auto pInv = make_unique<Investment>();
通过move()函数
unique_ptr<Investment> up1 = std::move(up);
注意:unique_ptr不能被复制或者拷贝,下面的代码将出错:
unique_ptr<Investment> up(new Investment()); //ok
unique_ptr<Investment> up1(up); //error, can not be copy
unique_ptr<Investment> up2 = up; //error, can not be assigned
但是,unique_ptr可以作为函数的返回值:
unique_ptr<Investment> GetPtr(); //function getthe unique pointer
unique_ptr<Investment> pInv = GetPtr(); // ok
二、自定义释放器
用如下方式使用带自定义资源释放的unique_ptr
auto delete_Investment = [](Investment* pInv)
{
pInv->getObjectType();
delete pInv;
};
unique_ptr<Investment,decltype(delete_Investment)> pInvest(nullptr,delete_Investment);
或者也可以使用函数指针
void deleteInv(Investment* pInv) {}
std::unique_ptr<Investment,void(*)(Investment*)>ptr(nullptr,deleteInv) ;
三、 unique_ptr 基本操作
unique_ptr<Investment> pInvestment; // 创建一个空的智能指针
pInvestment.reset(new Investment()); //"绑定”动态对象
Investment *pI = pInvestment.release(); //释放所有权
pI= nullptr; //显式销毁所指对象,同时智能指针变为空指针。
四、管理动态数组
由于unique_ptr有std::unique_ptr<T[]>的重载函数,所以它可以用来管理数组资源
unique_ptr<int[]> pArray(new int[3]{1,3,3});