智能指针 - 现代C++新特性总结

C++98中的智能指针通过一个模板类auto_ptr来实现,new操作符返回的指针可以交由它来管理,程序员不用再显式的调用delete,这在一定程度上避免了堆内存忘记释放的问题;不过auto_ptr有一些缺点,比如拷贝时返回一个左值,不能调用delete[]等

C++11中废弃了auto_ptr,改用unique_ptr、shared_ptr、weak_ptr等智能指针来自动回收堆分配对象,使内存管理更安全,智能指针的使用场景也变得更全面。

unique_ptr和shared_ptr

unique_ptr是唯一性智能指针,无法进行复制,但是可以移动。而shared_ptr是共享性智能指针,采用引用计数,可以拷贝和移动,移动时引用计数不会变化。

Example


#include <memory>
#include <iostream>
using namespace std;

int main()
{
    unique_ptr<int> up1(new int(11));        
    unique_ptr<int> up2 = up1;        //不能通过编译

    cout << *up1 << endl;                //11
    unique_ptr<int> up3 = move(up1);    //现在p3是数据唯一的unique_ptr智能指针

    cout << *up3 << endl;                //11
    cout << *up1 << endl;                //运行时错误
    up3.reset();                        //显式释放内存
    up1.reset();                        //不会导致运行时错误
    cout << *up3 << endl;                //运行时错误

    shared_ptr<int> sp1(new int(22));
    shared_ptr<int> sp2 = sp1;

    cout << *sp1 << endl;    //22
    cout << *sp2 << endl;    //22

    sp1.reset();
    cout << *sp2 << endl;    //22
}

//编译选项:g++ -std=c++11 unique_share.cpp

上例中,指针调用reset成员时,智能指针都可能释放其拥有的堆内存。

从代码中可以看出,unique_ptr和shared_ptr在对所占内存的共享上还是有一定区别的。

unique_ptr不能与其他unique_ptr类型的指针共享所指对象的内存。比如unique_ptr up2 = up1;不能通过编译,由于up1唯一地占有了new分配的堆内存,所以up2无法共享其“所有权”。这种“所有权”仅能通过标准库的move函数来转移。unique_ptr up3 = move(up1)语句中up3通过move函数夺去了up1的“所有权”,后段使用的*up1就会出现运行时错误。

而shared_ptr允许多个智能指针共享地“拥有”同一堆分配对象的内存。与unique_ptr不同的是,一旦一个shared_ptr指针放弃了“所有权”,其他的shared_ptr对对象内存的引用并不会受到影响。上例中的sp2很好说明了这个状况,sp1调用了reset成员,只是使得引用计数的降低,不会导致堆内存的释放。只有在引用计数归零时,shared_ptr才会真正地释放所占有的堆内存的空间。

weak_ptr

弱智能指针,通常指向一个共享性智能指针,当要使用所指向的共享性智能指针时,使用lock方法获取,并验证共享性智能指针的有效性。

Example:

#include <memory>
#include <iostream>
using namespace std;

void Check(weak_ptr<int> &wp)
{
    shared_ptr<int> sp = wp.lock();    //转换为shared_ptr<int>
    if (sp != nullptr)
        cout << "still " << *sp << endl;
    else
        cout << "pointer is invalid." << endl;
}

int main()
{
    shared_ptr<int> sp1(new int(22));
    shared_ptr<int> sp2 = sp1;
    weak_ptr<int> wp = sp1;    //指向shared_ptr<int>所指对象

    cout << *sp1 << endl;    //22
    cout << *sp2 << endl;    //22
    Check(wp);                //still 22

    sp1.reset();            
    cout << *sp2 << endl;    //22
    Check(wp);                //still 22

    sp2.reset();
    Check(wp);                //pointer is invalid

    return 0;
}

//编译选项:g++ -std=c++11 weak.cpp

上例中定义了2个shared_ptr——sp1和sp2,而weak_ptr wp同样指向该对象内存。当sp1和sp2有效时,调用wp的lock(),check会输出still 22。当分别调用sp1和sp2的reset()时,会导致堆内存对象的引用计数降为0。一旦引用计数归0,shared_ptr就会释放对内存空间,使之失效。

整个过程中,只有shared_ptr参与了引用计数,而weak_ptr没有影响其指向的内存的引用计数。因此可以验证shared_ptr指针的有效性。

简单情况下,程序员用unique_ptr代替以前使用auto_ptr就可以使用C++11中的智能指针。而shared_ptr及weak_ptr则可用在用户需要引用计数的地方。

posted @ 2018-06-23 16:46  心媛意码  阅读(320)  评论(0编辑  收藏  举报