智能指针模板类

    auto_ptr   unique_ptr  shared_ptr

    模板auto_ptr是C++98提供的解决方案,C++11已将其摒弃,并提供了另外两种解决方案。然而,虽然auto_ptr被摒弃,但它已使用了多年;同时,如果您的编译器不支持其他两种解决方案,auto_ptr将是唯一的选择。

    这三个智能指针模板都定义了类似指针的对象,可以将new获得(直接或者间接)的地址赋给这种对象。当智能指针过期时,其析构函数将使用delete来释放内存。

    要创建智能指针对象,必须包含头文件memory。

template<class X> class auto_ptr{
public:
    explicit auto_ptr(X* p=0) throw();
}
shared_ptr<double> pd;
double *p_reg = new double;
pd = p_reg; //不允许,implicit conversion
pd = shared_ptr<double>(p_reg); //允许,explicit conversion
shared_ptr<double> pshared = p_reg; //不允许,implicit conversion
shared_ptr<double> pshared(p_reg);  //允许,explicit conversion

    如果ps是一个智能指针对象,则可以对它执行解除引用操作(*ps),用它来访问结构成员(ps->puffIndex),将它赋给相同类型得常规指针。将智能指针对象赋给另一个同类型的指针指针对象可以通过编译,但会引起一个问题。

   

对于全部三种智能指针都应该避免下面的行为:

string vacation("i love china");
shared_ptr<string> pvac(&vacation);

pvac过期时,程序将把delete运算符用于非堆内存,这是错误的。

有关指针指针的注意事项

    对于下面的赋值语句:

auto_ptr<string> ps(new string("i love china));
auto_ptr<string> vocation;
vocation = ps;

    为了避免删除同一个对象两次,auto_ptr和unique_ptr使用的策略(unique_ptr策略更严格)是建立所有权概念,对于特定对象,只能有一个智能指针拥有它,赋值操作会转让所有权。

    shared_ptr使用的策略是创建智能更高的指针,跟踪引用特定对象的智能指针数。这称为引用计数。例如,赋值时,计数将加1,而指针过期时,计数将减1。仅当最后一个指针过期时,才调用delete。

    同样的策略也适用于赋值构造函数。

unique_ptr为何优于auto_ptr

     

unique_ptr<string> p3(new string("auto");
unique_ptr<string> p4;
p4 = p3; //非法

    编译器认为上述的p4=p3这条语句非法,因为如果在这之后p3的所有权将被剥夺,如果程序随后试图使用p3,将是一件坏事,因为p3不再指向有效的数据。而对于auto_ptr,p4=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被销毁。demo()返回的临时unique_ptr很快被销毁,没有机会使用它来访问无效的数据。编译器没理由禁止这种赋值。

   总之,程序试图将一个unique_ptr赋给另一个时,如果源unique_ptr是一个临时右值,编译器允许这样做。如果源unique_ptr将存在一段时间,则编译器将禁止这样做。

    

using namespace std;
unique_ptr<string> pu1(new string("Hi ho");
unique_ptr<string> pu2;
pu2 = pu1; //不允许
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string("yo!"));//允许

   这种随情况而异的行为表明,unique_ptr优于允许两种赋值的auto_ptr。要想在任何情况下强制使用一个unique_ptr赋值给令一个,可以使用C++标准库函数std::move()。

    unique_ptr能够区分安全和不安全的用法是因为它使用了C++11新增的移动构造函数和右值引用。

    相比于auto_ptr,unique_ptr还有另一个优点。它有一个可以用于数组的变体。模板auto_ptr使用delete而不是delete[ ] ,因此只能与new一起使用,而不能与new[ ]一起使用。但unique_ptr有使用new[ ]和delete[ ]的版本。

智能指针 是否支持new,delete 是否支持new[ ],delete[ ]
auto_ptr 支持 不支持
unique_ptr 支持 支持
shared_ptr 支持 不支持

如何选择智能指针

    如果程序要使用多个指向同一个对象的指针,应选择shared_ptr。如果程序不需要多个指向同一个对象的指针,则可使用unique_ptr。

    可将unique_ptr存储到STL容器中,只要不调用将一个unique_ptr赋值或者赋给另一个的方法或算法(如sort),例如可在程序中使用类似于下面的代码段:

unique_ptr<int> make_int(int n)
{
    return unique_ptr<int>(new int(n));
}

void show(unique_ptr<int> &pi)
{
    cout<<*pi<<' ';
}

int main()
{
    ......
    vector<unique_ptr<int>> vp(size);
    for(int i=0;i<vp.size();i++)
    {
        vp[i] = make_int(rand()%1000);
    }
    vp.push_back(make_int(rand()%1000));
    for_each(vp.begin(), vp.end(), show);
    ......
}

    其中的push_back()调用没有问题,因为它返回一个临时unique_ptr,该unique_ptr被赋给vp中的一个unique_ptr。另外,如果按值而不是按引用给show()传递对象,for_each()语句将非法,因为这将导致使用一个来自vp的非临时unique_ptr初始化pi,而这是不允许的。

    在unique_ptr为右值时,可将其赋给shared_ptr,这与将一个unique_ptr赋给另一个需要满足的条件相同。与前面一样,在下面的代码中,make_int()的返回类型为unique_ptr<int>:

unique_ptr<int> pup(make_int(rand()%1000)); //ok
shared_ptr<int> spp(pup);//不允许,pup是左值
shared_ptr<int> spr(make_int(rand()%1000)); //ok

    模板shared_ptr包含一个显式构造函数,可用于将右值unique_ptr转换为shared_ptr。shared_ptr将接管原来归unique_ptr所有的对象。

猜你喜欢

转载自blog.csdn.net/qq_25800311/article/details/85107681