一 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的删除器。