一 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的参数不是右值
}

至此,unique_ptr07的概述,初始化,成员函数用法,以及转化成shared_ptr的知识到此结束。下一篇将主讲unique_ptr的删除器。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐