1、auto_ptr
例如:
auto_ptr<string> p1(new string("auto")); auto_ptr<string> p2; p2 = p1;
执行后的局部变量:
上述代码执行到第三行之后,p2接管string对象的所有权,p1的所有权被剥夺。虽然,可防止p1和p2的
析构函数试图删除同一个对象;但是,程序如果试图删除p1,这是矛盾的,因为p1不再指向有效数据。
2、unique_ptr
例如:
unique_ptr<string> p3(new string("auto")); unique_ptr<string> p4; p4 = p3;
程序第三行提示错误,如果编译,则显示错误信息:尝试引用已删除的函数
编译器认为第三行非法,避免了p3不再指向有效数据的风险,因此unique_ptr 比 auto_ptr 更安全
(编译阶段的错误比潜在的程序崩溃更安全)
3、有时候,将一个智能指针赋值给另一个并不会留下 一个具有风险的悬挂指针
#include<memory> #include<iostream> using namespace std; unique_ptr<string> demo(const char* s) { unique_ptr<string> temp(new string(s)); return temp; } int main() { unique_ptr<string> ps; ps = demo("uniquely special"); return 1; }
demo() 返回一个临时的 unique_ptr , 然后ps接管了原本 函数返回的 unique_ptr指向的对象,而返回的unique_ptr被销毁。这都没问题,因为ps拥有了string对象的所有权。这里一个好处是demo()返回的临时unique_ptr很快被销毁,没有机会使用它来访问无效的数据。上述做法是编译器允许的程序试图将一个unique_ptr赋给另一个时候,如果源unique_ptr是个临时右值,编译器允许这样做;如果源unique_ptr将存在一段时间,编译器将会禁止这样做再看以下情况:
1 using namespace std; 2 unique_ptr<string> pu1(new string ("hi !")); 3 unique_ptr<string> pu2; 4 pu2 = pu1;//pu1将会存在下去,抱持悬空 5 unique_ptr<string> pu3; 6 pu3 = unique_ptr<string>(new string ("Yo"));//临时右值
这段代码编译不能通过。上述第4行将留下悬挂的 unique_ptr(pu1),将会有风险,pu2接管这个string;第6行则不会,因为调用unique_ptr的构造函数,该构造函数创建的临时对象将其所有权装让给pu3之后,将会被销毁。
小结:所以实际应用过程中,你最好不要用auto_ptr
4、c++标准库函数std::move()
在容器对象中,禁止使用auto_ptr,允许使用unique_ptr。
对于unique_ptr而言,容器算法试图对包含unique_ptr的容器执行 类似于上述第4行的操作,这将导致编译错误【要想做这种操作,解决方案是使用 move函数,请看下文】;
执行 类似于上述第6行的操作,这将OK。
对于auto_ptr而言,容器算法试图对包含auto_ptr的容器执行 类似于上述第4行的操作,将导致不确定行为和神秘崩溃。如果,你试图对包含unique_ptr的容器执行 类似于上述第4行的操作,我们将上述代码改为:
using namespace std; unique_ptr<string> pu1(new string ("hi !")); unique_ptr<string> pu2; //pu2 = pu1;//编译不能通过 pu2 = move(pu1);//pu1将会存在下去,抱持悬空
unique_ptr<string> pu3; pu3 = unique_ptr<string>(new string ("Yo"));//临时右值
总结:
使用 auto_ptr 指向对象,如果不慎错误使用,导致指针悬空,你很难发现,这种灾难会在代码运行阶段表现出来,可能你还不知道是这个原因导致;使用 unique_ptr指向对象,如果不慎错误使用,导致指针悬空,程序编译将不能通过,你将会发现对象指针悬空问题并及时作出更正。初此之外,我暂时觉得二者没什么卵区别。
对于unique_ptr的安全使用问题,我强烈建议你去查看《c++ primer plus》第18章节 ,后续补充博客。