c++: c++ unique_ptr使用

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指向。

一、初始化方式

  1. 通过new云算法或者普通指针

       unique_ptr<Investment> up(new Investment());

       或者

       Investment *pInv = new Investment();

unique_ptr<Investment> up1(pInv);

  1. 通过make_unique

auto pInv = make_unique<Investment>();

  1. 通过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 = [](InvestmentpInv)

{

       pInv->getObjectType();

       delete pInv;

    };

    unique_ptr<Investment,decltype(delete_Investment)> pInvest(nullptr,delete_Investment);

        或者也可以使用函数指针

    void deleteInv(InvestmentpInv) {}

    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_ptrstd::unique_ptr<T[]>的重载函数,所以它可以用来管理数组资源

unique_ptr<int[]> pArray(new int[3]{1,3,3});



猜你喜欢

转载自blog.csdn.net/dinnerhowe/article/details/79968204