C++ 智能指针auto_ptr、shared_ptr、unique_ptr《二》-----为何unique_ptr优于auto_ptr

时间:2021-02-14 19:44:47

1、auto_ptr

例如:

auto_ptr<string> p1(new string("auto"));
auto_ptr<string> p2;
p2 = p1;

执行后的局部变量:

C++ 智能指针auto_ptr、shared_ptr、unique_ptr《二》-----为何unique_ptr优于auto_ptr

上述代码执行到第三行之后,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章节 ,后续补充博客。