在C++11引入的新智能指针中,shared_ptr指针通过其计数机制实现与其他指针共享内存。此外,在C++11中还存在一个与之相应的智能指针——unique_prt:它同样可以自动管理内存,只是这块内存不和其他的unique_ptr分享。
1. unique_ptr指针的初始化 & 赋值
有了shared_ptr的基础,我们首先介绍unique_ptr指针的初始化、赋值:
1.1 初始化
如果观察unique_ptr的构造函数声明会发现,unique_ptr支持的构造函数和shared_ptr相差无几,这里直接举例:
1)初始化为空指针:
2)从指针创建:
3)从右值引用创建:
从输出结果可见,内存从p3转到了p4:
1.2 赋值
需要强调的是,由于unique_ptr对于内存的独占特性,unique_ptr不支持直接的赋值操作,而只能支持右值引用的赋值,基本形式如下:
unique_ptr<MyString> p1(new MyString("hello unique ptr"));
cout << "p1.get = " << p1.get() << endl;
unique_ptr<MyString> p2;
cout << "p2.get = " << p2.get() << endl;
p2 = move(p1);
cout << "p1.get = " << p1.get() << endl;
cout << "p2.get = " << p2.get() << endl;
/*
输出:
Constructed (hello unique ptr)!
p1.get = 0x7f8381c05a00
p2.get = 0x0
p1.get = 0x0
p2.get = 0x7f8381c05a00
Destructed (hello unique ptr)!
*/
需要说明的是,上述代码其实并没有什么实际意义,仅是为了说明unique_ptr采用了所有权独占机制。在真正的项目中,unique_ptr最常见的用法如下:
unique_ptr<MyString> GetUnique(string ms)
{
unique_ptr<MyString> tmp(new MyString(ms));
cout << tmp.get() << endl;
return tmp;
}
int main(){
unique_ptr<MyString> p1;
p1 = GetUnique("hello unique_ptr");
p1->Output();
cout << p1.get() << endl;
return 0;
}
/*
输出:
Constructed (hello unique_ptr)!
0x7fde05405a00
hello unique_ptr
0x7fde05405a00
Destructed (hello unique_ptr)!
*/
GetUnique()返回一个临时unique_ptr,然后p1接管了原本归返回的unique_ptr所有的对象,而返回时临时的 unique_ptr 被销毁,也就是说没有机会使用unique_ptr 来访问无效的数据,换句话来说,这种赋值是不会出现任何问题的,即没有理由禁止这种赋值。实际上,编译器确实允许这种赋值,这正是unique_ptr更聪明的地方。
总之,党程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做,比如:
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1; //#1 not allowed---编译器报错
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); //#2 allowed
其中#1留下悬挂的unique_ptr(pu1),这可能导致危害。而#2不会留下悬挂的unique_ptr,因为它调用 unique_ptr 的构造函数,该构造函数创建的临时对象在其所有权让给 pu3 后就会被销毁。