智能指针unique_ptr

一 unique_ptr

1 unique_ptr概述

独占式的概念(所有权);同一时刻只能有一个unique_ptr指向这个对象(这块内存),当这个unique_ptr被销毁时,它所指向的对象也被销毁。

2 unique_ptr的初始化

2.1 正常初始化

unique_ptr<string> p1(new string("Hello World"));

2.2 C++14新特性make_unique函数初始化

C++11中没有,C++14中才有make_unique,它不支持指定删除器的语法,如果不用删除器,建议优先选择使用,更高的性能。由于我的编译器最高支持C++11,所以没有这个函数。

unique_ptr<int> p1 = make_unique<int>(100);
auto p2 = make_unique<int>(200);

2.3 使用匿名对象初始化

//方法1
unique_ptr<string> p3=unique_ptr<string>(new string("Hello World"));
//方法2(调用函数返回匿名对象)
unique_ptr<string> return_unique_ptr(string str)
{   
    //从函数返回一个局部的unique_ptr对象,这种局部对象,系统会给我们再次生 
    //成一个临时的unique_ptr对象,调用unique_ptr的移动构造函数
    unique_ptr<string> pr(new string(str));
    return pr;  
}

unique_ptr<string> p4=return_unique_ptr("func return");

2.4 移动语义初始化

实际上移动语义和匿名对象初始化最终都是调用右值拷贝构造函数。

unique_ptr<string> ps1(new string("good luck"));
unique_ptr<string> ps2 = std::move(ps1);

2.5 错误的使用拷贝构造,等号重载初始化

由于unique_ptr是没有实现拷贝构造(或者具体说它只支持右值拷贝构造,所以上面才能使用move构造)和等号重载的,所以不能使用拷贝构造和等号重载初始化。

unique_ptr<string> p1(new string("Hello World"));
unique_ptr<string> p2;
//unique_ptr<string> pp3(p1);     //报错,左值拷贝构造并未实现
//p2=p1;                          //报错 =重载函数只写了声明没写函数体

3 unique_ptr的成员函数和其它操作的使用

3.1 release()

释放,调用后智能指针和其所指向对象的联系再无联系,但是该内存仍然存在有效。它会返回裸指针,但是该智能指针被置空。
返回的裸指针我们可以手工delete来释放,也可以用来初始化另外一个智能指针,或者给另外一个智能指针赋值。

unique_ptr<string> ps3(new string("good luck"));
unique_ptr<string> ps4(ps3.release());//此时ps4夺走ps3的使用权,ps3被置空。类似于移动语义,但区别是release返回裸指针,move返回本类型unique_ptr。
if(ps3==nullptr){
    cout<<"ps3被释放掉"<<endl;
}

3.2 reset()

reset()不带参数情况:释放智能指针所指向的对象(释放因为它是独占,而不像shared_ptr还需要考虑引用计数),并将智能指针置空。
reset()带参数时:释放智能指针所指向的对象,并将该智能指针指向新对象。

  //3 reset函数
    unique_ptr<string> ps5(new string("good luck"));
    unique_ptr<string> ps6(new string("good luck2"));
    /*
        首先ps6调用release后被置空,返回裸指针作为参数。然后
        由于ps5调用reset,ps5被置空,并指向新内存即ps6返回裸指针指向的那块内存
        所以我们打印ps5的数据应该是"good luck2"
    */
    ps5.reset(ps6.release());
    if(ps5==nullptr){
        cout<<"ps5被释放掉"<<endl;
    }
    if(ps6==nullptr){
        cout<<"ps6被释放掉,内存被ps5使用"<<endl;
    }
    cout << ps5->data() << endl;

3.3 nullptr的使用

实际上我们对于nullptr在上面已经使用过,用于比较。而这里也可以使用nullptr用于置空。所以nullptr目前在本篇可以作为1)比较。
2)置空:释放智能指针所指向的对象,并将智能指针置空。

class A {
public:
    A() {};
    A(int i) {
        m_i=i;
        cout<<"A"<<endl;
    };
    void SetI(int i) {m_i=i;};
    int GetI(){return m_i;}
    ~A() {
        cout<<"~A"<<endl;
    };
private:
    int m_i;
};

//4 nullptr的使用
unique_ptr<A> ps7(new A(522));
ps7 = nullptr; //释放ps7所指向的对象,并将ps7置空。
if(ps7 == nullptr){
    cout<<"ps7被置空,并且所指内存也被释放"<<endl;
}

3.4 指向数组

//由于unique_ptr的自定义删除器在下一篇将,所以这里简单描述
//unique_ptr<int,自定义删除器的类型> parr1(new int[5],自定义删除器);

unique_ptr<int[]> parr(new int[10]);
parr[0] = 12;
parr[1] = 12;

3.5 get()

get():返回智能指针中保存的裸指针。考虑到有些函数的参数需要内置的裸指针,所以引入该函数。

3.6 解引用(*)

解引用:获取该智能指针指向的对象,可以直接操作。

unique_ptr<string> ps8(new string("good"));
*ps8 = "good luck";

3.7 swap()

swap():交换两个智能指针所指向的对象。

unique_ptr<string> ps1(new string("good luck"));
unique_ptr<string> ps2(new string("good luck2"));
ps1.swap(ps2);
std::swap(ps1, ps2);//也可使用标准库的swap

4 如何将unique_ptr转换成shared_ptr类型

转换条件:如果unique_ptr为右值时,他就可以赋值给shared_ptr。
原因:因为shared_ptr包含一个显示构造函数,可用于将右值unique_ptr转换为shared_ptr,shared_ptr将接管原来归unqiue_ptr所拥有的对象。

auto myfunc()
{
    return unique_ptr<string>(new string("good luck")); //这是一个右值(临时对象都是右值)
}
 
void test18()
{
    shared_ptr<string> ps1 = myfunc(); //可以
    unique_ptr<int> pi1(new int(1));
    shared_ptr<int> pi2 = std::move(pi1); //可以,移动后pi1被置空

    // unique_ptr<int> pi3(new int(100));
    // shared_ptr<int> pi4(pi3);//不可以,原因pi4的参数不是右值
}

5.为什么优先选用unique_ptr

避免内存泄露(面试喜欢问)
避免更大开销

第一点相信很好理解,自动管理,不需要时即释放,甚至可以防止下面这样的情况:

int * p = new int(1111);
/*do something*/
delete p;

如果在do something的时候,出现了异常,退出了,那delete就永远没有执行的机会,就会造成内存泄露,而如果使用unique_ptr就不会有这样的困扰了。

第二点为何这么说?因为相比于shared_ptr,它的开销更小,甚至可以说和裸指针相当,它不需要维护引用计数的原子操作等等。

所以说,如果有可能,优先选用unique_ptr。

完整示例:https://blog.youkuaiyun.com/shaosunrise/article/details/85158249

总结

本文介绍了uniqueptr的基本使用情况和使用场景,它能够有效地避免内存泄露并且效率可控,因此如果能够满足需求,则优先选择unique\ptr。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值