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