c++ primer plus 第16章string 类和标准模板库,16.2.3 unique ptr为何优于auto ptr
c++ primer plus 第16章string 类和标准模板库,16.2.3 unique ptr为何优于auto ptr
16.2.3 unique ptr为何优于auto ptr
请看下面的语句:
auto ptr<string>pl(new string("auto");//#1
auto ptr<string> p2;//#2
p2 = p1i//#3
在语句#3中,p2接管string对象的所有权后,p1的所有权将被剥夺。前面说过,这是件好事,可防p1和p2的析构函数试图删除同一个对象;但如果程序随后试图使用p1,这将是件坏事,因为p1不再旨向有效的数据。
下面来看使用unique ptr的情况:
unique_ptr<string>p3(new string("auto");//#4
unique-ptr<string> p4;//#5
p4 = p3;//#6
编译器认为语句#6 非法,避免了p3不再指向有效数据的问题。因此,unique ptr比 auto ptr 更安全(编
阶段错误比潜在的程序崩溃更安全)。但有时候,将一个智能指针赋给另一个并不会留下危险的悬挂指针。假设有如下函数定义:
unique_ptr<string>demo(const char*s)
unique_ptr<string>temp(new string(s));return temp;
并假设编写了如下代码:
unique_ptr<string> ps;
ps = demo("Uniquely special");
demo( )返回一个临时 unique_ptr,然后 ps 接管了原本归返回的 unique_ptr 所有的对象,而返回的unique_ptr 被销毁。这没有问题,因为 ps拥有了 string 对象的所有权。但这里的另一个好处是,demo( )返回的临时 unique ptr 很快被销毁,没有机会使用它来访问无效的数据。换句话说,没有理由禁止这种赋值。神奇的是,编译器确实允许这种赋值!
总之,程序试图将一个 unique ptr 赋给另一个时,如果源 unique ptr 是个临时右值,编译器允许这样做;如果源uniqueptr将存在一段时间,编译器将禁止这样做:
using namespace std;
unique_ptr< string>pul(new string "Hi ho!");
unique_ptr< string> pu2;
pu2 = pul;//#1 not allowed
unique_ptr<string>pu3;
pu3 =unique_ptr<string>(new string "Yo!");//#2 allowed
语句#1将留下悬挂的 unique ptr(pul),这可能导致危害。语句#2 不会留下悬挂的 unique_ptr,因为它调用 unique ptr 的构造函数,该构造函数创建的临时对象在其所有权转让给pu后就会被销毁。这种随情况而异的行为表明,unique ptr优于允许两种赋值的 auto ptr。这也是禁止(只是一种建议,编译器并不禁止)在容器对象中使用 auto pt,但允许使用 unigue ptr 的原因。如果容器算法试图对包含 unique pt 的容器执行类似于语句#1的操作,将导致编译错误;如果算法试图执行类似于语句#2的操作,则不会有任何问题。而对于 auto ptr,类似于语句#1的操作可能导致不确定的行为和神秘的崩溃。
当然,您可能确实想执行类似于语句#1的操作。仅当以非智能的方式使用遗弃的智能指针(如解除引用时),这种赋值才不安全。要安全地重用这种指针,可给它赋新值。C++有一个标准库函数 std:move(),让您能够将一个 unique ptr 赋给另一个。下面是一个使用前述demo()函数的例子,该函数返回一个unique ptr对象:
using namespace std;
unique_ptr<string>psl,ps2;
ps1 = demo("Uniquely special");
ps2 =move(ps1);//enable assiqnment
ps1 =demo("and more");
cout<<*ps2<<*psl << endl;
您可能会问,unigue ptr 如何能够区分安全和不安全的用法呢?答案是它使用了C++11新增的移动构造函数和右值引用,这将在第18章讨论。
相比于 auto ptr,unique ptr 还有另一个优点。它有一个可用于数组的变体。别忘了,必须将 delete 和new配对,将 deleteП和 new[]配对。模板 auto ptr 使用 delete 而不是 delete[],因此只能与 new 一起使用,而不能与 new[]一起使用。但 unique ptr 有使用 new[]和 delete[]的版本:
std::unique_ptr< double[]>pda(new double(5));// will use delete []
警告:使用new分配内存时,才能使用auto ptr和shared ptr,使用 new[]分配内存时,不能使用它们。不使用new分配内存时,不能使用 auto ptr或 shared ptr;不使用new或new[分配内存时,不能使用unique ptro

被折叠的 条评论
为什么被折叠?



