C++ 智能指針實現(xiàn)分析

資源管理在軟件開發(fā)中歷來都是老大難問題,堆上內(nèi)存的管理尤其麻煩。現(xiàn)代編程語言引入了垃圾回收機(jī)制,如 Java,Python,Go 等,在內(nèi)存管理方面為開發(fā)者提供了極大的便利,開發(fā)者面對內(nèi)存泄漏問題的麻煩大大減少。

現(xiàn)代 C++ 的一大進(jìn)步就是在資源管理方面。開發(fā)者可以很方便地將資源的生命周期管理,如堆上內(nèi)存,文件描述符,Socket 句柄等,轉(zhuǎn)化為對象的生命周期管理,并借助于 C++ 的對象析夠機(jī)制,使得資源的生命周期管理大為簡化。

相對于其它現(xiàn)代編程語言,C++ 提供了操作符重載這種強(qiáng)大的工具,將普通的操作符與函數(shù)統(tǒng)一起來,使得資源管理更為方便。C++ 的對象析夠機(jī)制,總是能夠確保一個對象在超出它的作用域之后被釋放掉,如函數(shù)的局部對象在函數(shù)返回后必然被析夠,堆上的對象可以確保在調(diào)用它的 delete 之后被釋放掉,這相對于垃圾回收機(jī)制更為可靠。本文主要討論堆上內(nèi)存的管理。

首先來看一下堆上內(nèi)存管理的難點。堆上對象的分配,通常不是什么太大的問題,分配的點總是比較容易分析,比較麻煩的是對象的釋放。如果一個對象只被另外一個對象使用,則對象的生命周期管理也比較容易。當(dāng)一個堆上分配的對象,同時為多個其它對象,特別是同時為多個不同線程訪問時,釋放時機(jī)的選擇就比較棘手了。

一個對象持有指向某個堆上對象的指針時,它根本無法判斷這個對象是否已經(jīng)被釋放。一個堆上對象被某個對象釋放,其它對象再去訪問它時,比較好的情況是,程序立即由于 SIGSEGV 而崩潰,更糟糕的情況則是,程序在一段時間內(nèi)繼續(xù)運行,最后在莫名其妙的位置發(fā)生崩潰或者死鎖,這還會給問題診斷制造麻煩。

如果訪問某個堆上對象的所有對象都沒有去釋放它,則將會造成內(nèi)存泄漏。內(nèi)存資源將隨著程序運行時間的流逝,而逐漸被消耗殆盡。

現(xiàn)代 C++ 通過智能指針管理堆上內(nèi)存。智能指針并不是真正的指針,而是一個類對象,但它的行為基本上就像普通的指針那樣。通常我們對指針?biāo)龅牟僮髦饕校和ㄟ^解引用操作符 -> 訪問指針指向的對象的成員,通過 * 操作符獲得指針指向的對象的引用,復(fù)制,邏輯判斷如相等性判斷、不等性判斷等,指針比較等。智能指針可以提供所有這些操作,但不像普通指針那樣由編程語言提供,而是借助于操作符重載,實現(xiàn)響應(yīng)的操作符函數(shù)。

在智能指針的使用上,通常我們先在堆上分配一個對象,將指向?qū)ο蟮闹羔樈o智能指針對象,智能指針對象在釋放時,根據(jù)需要釋放我們在堆上分配的對象。以此堆上資源生命周期管理問題被轉(zhuǎn)換為了智能指針對象的生命周期管理問題。

當(dāng)然智能指針也有不好的地方,或者說存在風(fēng)險的地方。如果兩個用智能指針管理的對象,它們相互之間通過智能指針引用對方,將難免會造成內(nèi)存泄漏。要避免這種問題,需要仔細(xì)地考慮對象間的關(guān)系,并適當(dāng)使用 weak_ptr。智能指針的使用也還是需要多加小心。

本文討論智能指針的使用和實現(xiàn)。C++ 中的智能指針,就對待所管理指針的方式而言,可分為兩大類。一是如 C++ STL 中的 std::unique_ptr,boost 的 boost::scoped_ptrboost::scoped_array 這樣,在智能指針對象銷毀時,直接釋放所管理的堆上對象的。二是如 C++ STL 中的 std::shared_ptr ,Poco 庫的 Poco::AutoPtr, Android framework 中的 sp 這樣,基于引用計數(shù)實現(xiàn),在智能指針對象復(fù)制時增加引用計數(shù),在智能指針對象釋放時減小引用計數(shù),只有當(dāng)引用計數(shù)減小為 0 時,才釋放對象的。

基于引用計數(shù)實現(xiàn)的智能指針,依據(jù)其侵入性的不同,又分為兩類:一是具有一定的侵入性,要求被智能指針管理的對象的類繼承某個特定類的,如 Poco 庫里的 Poco::AutoPtr 和 android 中的 sp;二是對被管理的對象沒有任何要求的,如 C++ STL 中的 std::shared_ptr

本文分析幾種智能指針的使用與實現(xiàn):boost 的 boost::scoped_ptr,Poco 庫的 Poco::AutoPtr, Android framework 中的 sp,及 C++ STL 的 std::shared_ptr。其中 boost 的 boost::scoped_ptr 基于 boost 1.58.0 的代碼來分析;Poco 庫的 Poco::AutoPtr 基于 1.6.0;Android 的 sp 基于 android 7.1.1 r22 ;C++ STL 的 std::shared_ptr 則基于我的 Ubuntu Linux GCC 5.4.0 帶的 STL 實現(xiàn)。

boost::scoped_ptr 的使用及實現(xiàn)

先來看一下 boost::scoped_ptr 用法:

#include <iostream>

#include <boost/smart_ptr.hpp>

class TestObj {
public:
    TestObj();
    virtual ~TestObj();
    int i;
};

TestObj::TestObj() : i (32412) {
  std::cout << "Create TestObj" << this << std::endl;
}

TestObj::~TestObj() {
  std::cout << "Release TestObj"  << this << std::endl;
}

int main() {
  boost::scoped_ptr<TestObj> objPtr(new TestObj);
  std::cout << "TestObj i = " << objPtr->i << std::endl;
  std::cout << "TestObj i = " << (*objPtr).i << std::endl;
  return 0;
}

在創(chuàng)建 boost::scoped_ptr 對象的時候,把需要由它管理的堆上對象的指針傳給構(gòu)造函數(shù),在 boost::scoped_ptr 對象析夠的時候,它所管理的指針會被自動 delete。我們可以通過 boost::scoped_ptr 對象像使用普通指針那樣訪問被管理的對象的成員,獲得對象的引用。boost::scoped_ptr 是一種沒有任何侵入性的智能指針,它可以管理任何類型的堆上對象的指針。

boost::scoped_ptr 是一個模板類,其代碼位于
boost/smart_ptr/scoped_ptr.hpp, 如下面這樣:

namespace boost
{

// Debug hooks

#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)

void sp_scalar_constructor_hook(void * p);
void sp_scalar_destructor_hook(void * p);

#endif

//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
//  of the object pointed to, either on destruction of the scoped_ptr or via
//  an explicit reset(). scoped_ptr is a simple solution for simple needs;
//  use shared_ptr or std::auto_ptr if your needs are more complex.

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

    T * px;

    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 ): px( p ) // never throws
    {
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
        boost::sp_scalar_constructor_hook( px );
#endif
    }

#ifndef BOOST_NO_AUTO_PTR

    explicit scoped_ptr( std::auto_ptr<T> p ) BOOST_NOEXCEPT : px( p.release() )
    {
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
        boost::sp_scalar_constructor_hook( px );
#endif
    }

#endif

    ~scoped_ptr() // never throws
    {
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
        boost::sp_scalar_destructor_hook( px );
#endif
        boost::checked_delete( px );
    }

    void reset(T * p = 0) // never throws
    {
        BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
        this_type(p).swap(*this);
    }

    T & operator*() const // never throws
    {
        BOOST_ASSERT( px != 0 );
        return *px;
    }

    T * operator->() const // never throws
    {
        BOOST_ASSERT( px != 0 );
        return px;
    }

    T * get() const BOOST_NOEXCEPT
    {
        return px;
    }

// implicit conversion to "bool"
#include <boost/smart_ptr/detail/operator_bool.hpp>

    void swap(scoped_ptr & b) BOOST_NOEXCEPT
    {
        T * tmp = b.px;
        b.px = px;
        px = tmp;
    }
};

#if !defined( BOOST_NO_CXX11_NULLPTR )

template<class T> inline bool operator==( scoped_ptr<T> const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT
{
    return p.get() == 0;
}

template<class T> inline bool operator==( boost::detail::sp_nullptr_t, scoped_ptr<T> const & p ) BOOST_NOEXCEPT
{
    return p.get() == 0;
}

template<class T> inline bool operator!=( scoped_ptr<T> const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT
{
    return p.get() != 0;
}

template<class T> inline bool operator!=( boost::detail::sp_nullptr_t, scoped_ptr<T> const & p ) BOOST_NOEXCEPT
{
    return p.get() != 0;
}

#endif

template<class T> inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) BOOST_NOEXCEPT
{
    a.swap(b);
}

// get_pointer(p) is a generic way to say p.get()

template<class T> inline T * get_pointer(scoped_ptr<T> const & p) BOOST_NOEXCEPT
{
    return p.get();
}

} // namespace boost

Poco 庫 Poco::AutoPtr 的用法及實現(xiàn)

先來看一下用法:

class TestObj: public RefCountedObject {
public:
    TestObj();
    virtual ~TestObj();
};

TestObj::TestObj() {

}

TestObj::~TestObj() {
}

typedef Poco::AutoPtr<TestObj> TestObjPtr;
typedef list<TestObjPtr> TestObjList;

void test_ap() {
    Poco::AutoPtr<TestObj> ptr = new TestObj;
    cout << "Initial refcount = " << ptr->referenceCount() << endl;

    Poco::AutoPtr<TestObj> ptr2 = ptr;
    cout << "Copy one time refcount = " << ptr->referenceCount() << endl;

    list<Poco::AutoPtr<TestObj> > testObjList;
    testObjList.push_back(ptr);
    cout << "Push into a list refcount = " << ptr->referenceCount() << endl;

    testObjList.remove(ptr);
    cout << "Remove from a list refcount = " << ptr->referenceCount() << endl;

    ptr2 = new TestObj;
    cout << "refcount = " << ptr->referenceCount() << endl;

    TestObjPtr ptr3;
    ptr3 = ptr2;
    cout << "ptr2 refcount = " << ptr2->referenceCount() << endl;
    ptr3 = new TestObj;
    cout << "ptr2 refcount = " << ptr2->referenceCount() << endl;
    ptr3 = ptr2;
    cout << "ptr2 refcount = " << ptr2->referenceCount() << endl;
}

如下是上面這段code執(zhí)行的結(jié)果:

Initial refcount = 1
Copy one time refcount = 2
Push into a list refcount = 3
Remove from a list refcount = 2
refcount = 1
ptr2 refcount = 2
ptr2 refcount = 1
ptr2 refcount = 2

可以看到對象的引用計數(shù)隨著流程的執(zhí)行而改變,AutoPtr對象每復(fù)制一次,其管理的對象的引用計數(shù)就加一,而AutoPtr對象每釋放一次,其管理的對象的引用計數(shù)就減一。

接著來具體說明一下要如何使用AutoPtr。首先,由智能指針來管理其對象釋放的class需要繼承Poco庫的RefCountedObject。AutoPtr是一種基于引用計數(shù)的堆對象管理機(jī)制,因而,總要有個地方來存放一個對象的引用次數(shù)。AutoPtr管理的對象,用于記錄引用計數(shù)的變量存放在該對象中,但那個變量繼承自RefCountedObject(RefCountedObject提供的當(dāng)然不止是這樣的一個變量)。

一定要繼承RefCountedObject才能使用Poco的AutoPtr嗎?答案是不一定。但要由AutoPtr管理其對象的類,一定要符合模板AutoPtr所要求的隱式接口。具體點說,就是要提供RefCountedObject提供的接口,就像網(wǎng)上有些地方看到的例子,讓那些類自己定義那些函數(shù)。當(dāng)然接口的行為也要與RefCountedObject基本一致,比如,增加引用計數(shù),減少引用計數(shù),在引用計數(shù)減小為0時釋放對象,否則的話,AutoPtr的作用也不能真正展現(xiàn)。

然后就可以RAII(資源獲取即初始化),使用AutoPtr來管理new的對象了。我們可以放心的像使用Java里面的對象一樣使用AutoPtr,而不用擔(dān)心會有memory leak。

接著我們來看Poco::AutoPtr這套機(jī)制的實現(xiàn)。主要就是class RefCountedObject和模板AutoPtr的定義。先來看RefCountedObject的定義與實現(xiàn):

#include "Poco/Foundation.h"
#include "Poco/AtomicCounter.h"


namespace Poco {

class Foundation_API RefCountedObject
/// A base class for objects that employ
/// reference counting based garbage collection.
///
/// Reference-counted objects inhibit construction
/// by copying and assignment.
{
public:
    RefCountedObject();
    /// Creates the RefCountedObject.
    /// The initial reference count is one.

    void duplicate() const;
    /// Increments the object's reference count.

    void release() const throw ();
    /// Decrements the object's reference count
    /// and deletes the object if the count
    /// reaches zero.

    int referenceCount() const;
    /// Returns the reference count.

protected:
    virtual ~RefCountedObject();
    /// Destroys the RefCountedObject.

private:
    RefCountedObject(const RefCountedObject&);
    RefCountedObject& operator =(const RefCountedObject&);

    mutable AtomicCounter _counter;
};

//
// inlines
//
inline int RefCountedObject::referenceCount() const {
    return _counter.value();
}

inline void RefCountedObject::duplicate() const {
    ++_counter;
}

inline void RefCountedObject::release() const throw () {
    try {
        if (--_counter == 0)
            delete this;
    } catch (...) {
        poco_unexpected();
    }
}

} // namespace Poco

下面是這個class的實現(xiàn)文件:

RefCountedObject::RefCountedObject(): _counter(1)
{
}

RefCountedObject::~RefCountedObject()
{
}

這個類只有一個原子類型AtomicCounter的成員變量_counter,用來記錄對象被引用的次數(shù)??梢钥吹剿潜宦暶鳛閙utable的,也就是說,即使是對于const的對象,在const方法中,也可以修改這個變量的值。

這個類提供了三個操作duplicate()、release()和referenceCount(),用來修改或讀取_counter的值。這三個操作全都被聲明為const,配合聲明為mutable的_counter,使得AutoPtr這套機(jī)制,即使是對于new的const class也一樣可用。duplicate()操作中,會增加引用計數(shù),release()操作中會減少引用計數(shù),referenceCount()操作則會將對象當(dāng)前被引用的次數(shù)返回給調(diào)用者。在release()操作中,如果引用技術(shù)減到了0,當(dāng)前對象會被delete掉。這些操作究竟會在什么地方調(diào)用到呢?答案是AutoPtr,后面看到模板AutoPtr的定義就能明白了。

這個class還采用了一些方法來阻止對于它的繼承體系中對象的復(fù)制行為??梢钥吹?,它聲明了private的copy構(gòu)造函數(shù)和賦值操作符,但兩個函數(shù)都沒有被定義。private聲明可以在編譯期阻止那些對于這個class的private成員沒有訪問權(quán)限的部分復(fù)制對象,而有意的不定義這兩個函數(shù),則可以在鏈接期阻止對這個class的private成員有訪問權(quán)限的部分,比如一些friend class,friend方法,或內(nèi)部的一些函數(shù)復(fù)制對象。

接著來看AutoPtr模板的定義:

template<class C>
class AutoPtr
/// AutoPtr is a "smart" pointer for classes implementing
/// reference counting based garbage collection.
/// To be usable with the AutoPtr template, a class must
/// implement the following behaviour:
/// A class must maintain a reference count.
/// The constructors of the object initialize the reference
/// count to one.
/// The class must implement a public duplicate() method:
///     void duplicate();
/// that increments the reference count by one.
/// The class must implement a public release() method:
///     void release()
/// that decrements the reference count by one, and,
/// if the reference count reaches zero, deletes the
/// object.
///
/// AutoPtr works in the following way:
/// If an AutoPtr is assigned an ordinary pointer to
/// an object (via the constructor or the assignment operator),
/// it takes ownership of the object and the object's reference 
/// count remains unchanged.
/// If the AutoPtr is assigned another AutoPtr, the
/// object's reference count is incremented by one by
/// calling duplicate() on its object.
/// The destructor of AutoPtr calls release() on its
/// object.
/// AutoPtr supports dereferencing with both the ->
/// and the * operator. An attempt to dereference a null
/// AutoPtr results in a NullPointerException being thrown.
/// AutoPtr also implements all relational operators.
/// Note that AutoPtr allows casting of its encapsulated data types.
{
public:
    AutoPtr() :
            _ptr(0) {
    }

    AutoPtr(C* ptr) :
            _ptr(ptr) {
    }

    AutoPtr(C* ptr, bool shared) :
            _ptr(ptr) {
        if (shared && _ptr)
            _ptr->duplicate();
    }

    AutoPtr(const AutoPtr& ptr) :
            _ptr(ptr._ptr) {
        if (_ptr)
            _ptr->duplicate();
    }

    template<class Other>
    AutoPtr(const AutoPtr<Other>& ptr) :
            _ptr(const_cast<Other*>(ptr.get())) {
        if (_ptr)
            _ptr->duplicate();
    }

    ~AutoPtr() {
        if (_ptr)
            _ptr->release();
    }

    AutoPtr& assign(C* ptr) {
        if (_ptr != ptr) {
            if (_ptr)
                _ptr->release();
            _ptr = ptr;
        }
        return *this;
    }

    AutoPtr& assign(C* ptr, bool shared) {
        if (_ptr != ptr) {
            if (_ptr)
                _ptr->release();
            _ptr = ptr;
            if (shared && _ptr)
                _ptr->duplicate();
        }
        return *this;
    }

    AutoPtr& assign(const AutoPtr& ptr) {
        if (&ptr != this) {
            if (_ptr)
                _ptr->release();
            _ptr = ptr._ptr;
            if (_ptr)
                _ptr->duplicate();
        }
        return *this;
    }

    template<class Other>
    AutoPtr& assign(const AutoPtr<Other>& ptr) {
        if (ptr.get() != _ptr) {
            if (_ptr)
                _ptr->release();
            _ptr = const_cast<Other*>(ptr.get());
            if (_ptr)
                _ptr->duplicate();
        }
        return *this;
    }

    AutoPtr& operator =(C* ptr) {
        return assign(ptr);
    }

    AutoPtr& operator =(const AutoPtr& ptr) {
        return assign(ptr);
    }

    template<class Other>
    AutoPtr& operator =(const AutoPtr<Other>& ptr) {
        return assign<Other>(ptr);
    }

    void swap(AutoPtr& ptr) {
        std::swap(_ptr, ptr._ptr);
    }

    template<class Other>
    AutoPtr<Other> cast() const
    /// Casts the AutoPtr via a dynamic cast to the given type.
    /// Returns an AutoPtr containing NULL if the cast fails.
    /// Example: (assume class Sub: public Super)
    ///    AutoPtr<Super> super(new Sub());
    ///    AutoPtr<Sub> sub = super.cast<Sub>();
    ///    poco_assert (sub.get());
    {
        Other* pOther = dynamic_cast<Other*>(_ptr);
        return AutoPtr<Other>(pOther, true);
    }

    template<class Other>
    AutoPtr<Other> unsafeCast() const
    /// Casts the AutoPtr via a static cast to the given type.
    /// Example: (assume class Sub: public Super)
    ///    AutoPtr<Super> super(new Sub());
    ///    AutoPtr<Sub> sub = super.unsafeCast<Sub>();
    ///    poco_assert (sub.get());
    {
        Other* pOther = static_cast<Other*>(_ptr);
        return AutoPtr<Other>(pOther, true);
    }

    C* operator ->() {
        if (_ptr)
            return _ptr;
        else
            throw NullPointerException();
    }

    const C* operator ->() const {
        if (_ptr)
            return _ptr;
        else
            throw NullPointerException();
    }

    C& operator *() {
        if (_ptr)
            return *_ptr;
        else
            throw NullPointerException();
    }

    const C& operator *() const {
        if (_ptr)
            return *_ptr;
        else
            throw NullPointerException();
    }

    C* get() {
        return _ptr;
    }

    const C* get() const {
        return _ptr;
    }

    operator C*() {
        return _ptr;
    }

    operator const C*() const {
        return _ptr;
    }

    bool operator !() const {
        return _ptr == 0;
    }

    bool isNull() const {
        return _ptr == 0;
    }

    C* duplicate() {
        if (_ptr)
            _ptr->duplicate();
        return _ptr;
    }

    bool operator ==(const AutoPtr& ptr) const {
        return _ptr == ptr._ptr;
    }

    bool operator ==(const C* ptr) const {
        return _ptr == ptr;
    }

    bool operator ==(C* ptr) const {
        return _ptr == ptr;
    }

    bool operator !=(const AutoPtr& ptr) const {
        return _ptr != ptr._ptr;
    }

    bool operator !=(const C* ptr) const {
        return _ptr != ptr;
    }

    bool operator !=(C* ptr) const {
        return _ptr != ptr;
    }

    bool operator <(const AutoPtr& ptr) const {
        return _ptr < ptr._ptr;
    }

    bool operator <(const C* ptr) const {
        return _ptr < ptr;
    }

    bool operator <(C* ptr) const {
        return _ptr < ptr;
    }

    bool operator <=(const AutoPtr& ptr) const {
        return _ptr <= ptr._ptr;
    }

    bool operator <=(const C* ptr) const {
        return _ptr <= ptr;
    }

    bool operator <=(C* ptr) const {
        return _ptr <= ptr;
    }

    bool operator >(const AutoPtr& ptr) const {
        return _ptr > ptr._ptr;
    }

    bool operator >(const C* ptr) const {
        return _ptr > ptr;
    }

    bool operator >(C* ptr) const {
        return _ptr > ptr;
    }

    bool operator >=(const AutoPtr& ptr) const {
        return _ptr >= ptr._ptr;
    }

    bool operator >=(const C* ptr) const {
        return _ptr >= ptr;
    }

    bool operator >=(C* ptr) const {
        return _ptr >= ptr;
    }

private:
    C* _ptr;
};

template<class C>
inline void swap(AutoPtr<C>& p1, AutoPtr<C>& p2) {
    p1.swap(p2);
}

這個模板類,主要實現(xiàn)了一些創(chuàng)建、復(fù)制、銷毀動作及其它的一些操作符。創(chuàng)建、復(fù)制(copy構(gòu)造函數(shù)及賦值操作符)及銷毀動作是智能指針行為的核心之所在,創(chuàng)建、復(fù)制時,需要正確地增加對象的引用計數(shù),而在銷毀時,則要減少只能指針。

既然稱之為智能指針,那自然就不能少了常規(guī)的指針都有的一些操作方式,比如解引用或通過箭頭操作符訪問對象成員,因而,不出意料的這個模板類也重載了operator ->和operator 這兩個操作符。它還提供了類型智能指針到對象類型指針的轉(zhuǎn)換操作operator C/operator const C*,及獲取對象指針的操作。

除此之外,它還提供了一系列基于指針值的比較操作。

AutoPtr接收單個指針作為參數(shù)的構(gòu)造函數(shù),使得編譯器可以實施由一個對象指針到智能指針的隱式類型轉(zhuǎn)換。所造成的問題就是,一不小心,編譯器自己創(chuàng)建了一個AutoPtr,但對象的引用計數(shù)沒有增加,后續(xù)智能指針對象在銷毀的時候,它所追蹤的對象的引用計數(shù)會提前減小到0,然后對象會被提前釋放。比如傳遞this指針,調(diào)用一個接受該對象的智能指針為參數(shù)的函數(shù)。但其實這種情況下,是應(yīng)該要調(diào)用那個需要一個額外的bool型參數(shù)的構(gòu)造函數(shù)來創(chuàng)建智能指針對象,以使得對象的引用計數(shù)能被適當(dāng)?shù)脑黾拥摹S墒褂谜呓嵌葋砜?,Poco的AutoPtr的這種設(shè)計增加了用戶使用它的風(fēng)險,因而將AutoPtr的AutoPtr(C* ptr)構(gòu)造函數(shù)聲明為explicit以擋掉編譯器的隱式類型轉(zhuǎn)換似乎要更好,更安全一點。

android sp 的用法及實現(xiàn)

android sp 的用法

std::tr1::shared_ptr 的用法及實現(xiàn)

std::tr1::shared_ptr 的用法及實現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • C++ 智能指針詳解 一、簡介由于 C++ 語言沒有自動內(nèi)存回收機(jī)制,程序員每次 new 出來的內(nèi)存都要手動 de...
    yangqi916閱讀 1,448評論 0 2
  • 導(dǎo)讀## 最近在補(bǔ)看《C++ Primer Plus》第六版,這的確是本好書,其中關(guān)于智能指針的章節(jié)解析的非常清晰...
    小敏紙閱讀 2,066評論 1 12
  • 1. 什么是智能指針? 智能指針是行為類似于指針的類對象,但這種對象還有其他功能。 2. 為什么設(shè)計智能指針? 引...
    MinoyJet閱讀 696評論 0 1
  • 原作者:Babu_Abdulsalam 本文翻譯自CodeProject,轉(zhuǎn)載請注明出處。 引入### Ooops...
    卡巴拉的樹閱讀 30,330評論 13 74
  • 本文版權(quán)歸 liancheng 所有,如有轉(zhuǎn)載請按如下方式標(biāo)明原創(chuàng)作者及出處,以示尊重!!原創(chuàng)作者:lianche...
    周肅閱讀 7,862評論 2 6

友情鏈接更多精彩內(nèi)容