Boost库——四种智能指针的对比和注意点


1.智能指针类型

C++98最早的智能指针auto_ptr已被废止。
C++11/14标准中的unique_ptr、shared_ptr和weak_ptr,源于boost中的scoped_ptr、shared_ptr和weak_ptr(boost中共有6种智能指针)

2.scoped_ptr(scoped_array)和unique_ptr

2.1 scoped_ptr(scoped_array)

scoped_ptr包装了new在堆上的动态对象,能保证对象能在任何时候都被正确的删除。scoped_ptr的所有权更严格,不能转让。scoped_ptr,看名字,该智能指针只可以在本作用域内使用,不希望被转让。scoped_array和scoped_ptr的唯一不同是scoped_array管理数组对象。不建议使用scoped_array,可用vector替代。

scoped_ptr摘要:


template<class T> class scoped_ptr // noncopyable
{
private:

    T * px;//原始指针
    //禁止对智能指针的拷贝,保证被它管理的指针不被转让所有权。
    //如果一个类持有scoped_ptr成员,它也是禁止拷贝赋值的。
    scoped_ptr(scoped_ptr const &);//拷贝构造私有化
    scoped_ptr & operator=(scoped_ptr const &);//赋值操作私有化

    typedef scoped_ptr<T> this_type;

    void operator==( scoped_ptr const& ) const;
    void operator!=( scoped_ptr const& ) const;

public:

    typedef T element_type;

    explicit scoped_ptr( T * p = 0 ); // never throws


    explicit scoped_ptr( std::auto_ptr<T> p );

    ~scoped_ptr(); // never throws

    void reset(T * p = 0); // never throws,重置指针,一般不用
    //模拟原始指针操作,保存空指针时2操作未定义
    T & operator*() const; // never throws
    T * operator->() const; // never throws

    T * get() const;//获得原始指针

    void swap(scoped_ptr & b);//交换指针
};

2.2 unique_ptr

std::unique_ptr是C++11中新定义的智能指针,用于取代auto_ptr。unique_ptr不仅可以代理new创建的单个对象,也可以代理new[]创建的数组对象,就是说它结合了scoped_ptr和scoped_array两者的能力。

unique_ptr的基本能力跟scoped_ptr一样,同样可以在作用域内管理指针,也不允许拷贝和赋值。

unique_ptr类摘要:

template <class T, class D = default_delete<T> >
class unique_ptr
{
   public:
   unique_ptr(const unique_ptr&) = delete;//禁止拷贝
   unique_ptr& operator=(const unique_ptr&) = delete;//禁止赋值

   public:
   BOOST_CONSTEXPR unique_ptr();
   BOOST_CONSTEXPR unique_ptr(BOOST_MOVE_DOC0PTR(bmupd::nullptr_type)) BOOST_NOEXCEPT;

   unique_ptr(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT;

   unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT;

   operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u) BOOST_NOEXCEPT;//转移语义赋值

   pointer operator->() const BOOST_NOEXCEPT;

   pointer get() const BOOST_NOEXCEPT;

   pointer release() BOOST_NOEXCEPT;//释放指针管理权

   reset(Pointer p) BOOST_NOEXCEPT;

   void swap(unique_ptr& u) BOOST_NOEXCEPT;

3 shared_ptr和weak_ptr

3.1 shared_ptr

shared_ptr是最像指针的智能指针。shared_ptr和scoped_ptr一样包装了new在堆上的动态对象,也不可以管理new[]产生的数组指针,也没有指针算术操作。但是shared_ptr实现了引用计数,可以自由拷贝赋值,在任意地方共享它,当没有代码使用它(引用计数为0)时,它才删除被包装的动态对象。shared_ptr可以被放在标准容器中,STL容器存储指针的标准做法。

3.1.1 工厂函数make_shared

shared_ptr消除了显示调用delete,但是没有消除显示调用new,boost提供一个工厂函数make_shared来消除显式new调用。例子:

void fun()
{
    auto sp = boost::make_shared<string>("make_shared");//创建string共享指针
    auto spv = boost::make_shared< vector<int> >(10,2);//vector共享指针
}

3.2 weak_ptr

weak_ptr是为了配合shared_ptr而引入的,它没有普通指针的行为,没重载*和->。它最大的作用是协助shared_ptr工作,像旁观者一样观测资源的使用情况。weak_ptrk可以从一个shared_ptr或者一个weak_ptr对象构造,获得对象资源观测权。但是weak_ptr并没有共享资源,它的构造不会引起引用计数的增加,也不会让引用计数减少,它只是静静的观察者。

template<class T> class weak_ptr
{
private:
    typedef weak_ptr<T> this_type;

public:
    weak_ptr();

    ~weak_ptr();

    weak_ptr( weak_ptr const & r );

    weak_ptr & operator=( weak_ptr const & r );

    weak_ptr( weak_ptr<Y> const & r );

    shared_ptr<T> lock() const;//获取shared_ptr,把弱关系转为强关系,操作资源

    long use_count() const;//引用计数

    bool expired() const;//是否失效指针

    void reset();//重置指针

    void swap(this_type & other);

    element_type * px;            // contained pointer
    boost::detail::weak_count pn; // reference counter

};  // weak_ptr

template<class T, class U> inline bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b);

例子:

class self_shared: public enable_shared_from_this<self_shared>
{
public:
  int n;
  void fun();
};

int main()
{
    auto sp = make_shared<self_shared>(123);
    sp->fun();

    auto p = sp->shared_from_this();
    p->fun();

    //不能对普通对象使用shared_from_this
    self_shared s;
    auto ps = s->shared_from_this();//错误,shared_ptr会在析构时试图删除一个栈对象

    return 0;
}

3.3 打破循环引用

有时候代码会出现循环引用,这时候shared_ptr的引用计数就会失效,导致不能正确释放资源。例如:

class node
{
    public:
    ~node(){cout<<"deleted.\n";}
    typedef shared_ptr<node> ptr_type;
    ptr_type next;
};

int main()
{
    auto p1 = make_shared<node>();
    auto p2 = make_shared<node>();

    p1->next = p2;//形成循环链表
    p2->next = p1;

    cout<<p1->use_count()<<endl;//=2
    cout<<p2->use_count()<<endl;//=2
    return 0;
}

两个node对象都互相持有对方的引用,每个shared_ptr对象的引用计数都是2,因此在析构时不能减为0,不会调用删除操作,导致内存泄漏。这个时候我们可以使用weak_ptr,因为它不会增加引用计数,这强引用变为弱引用,在可能循环的地方打破循环,真正需要shared_ptr的时候调用weak_ptr的lock()函数。

//修改以上
    typedef weak_ptr<node> ptr_type;

    p1->next = p2;//形成循环链表
    p2->next = p1;//weak_ptr所以正常

    if (!p1->next->expired())//检查弱引用是否有效
    {
        auto p3 = p1->next->lock();//获得强引用
    }

    //退出后,shared_ptr都正确析构


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM