歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Boost--內存管理--(1)智能指針

Boost--內存管理--(1)智能指針

日期:2017/3/1 9:19:35   编辑:Linux編程

(一)RAII機制  

  RAII機制(資源獲取即初始化,Resource Acquisition Is Initialization),在使用資源的類的構造函數中申請資源,然後使用,最後在析構函數中釋放資源。

  如果對象實在創建在棧上(如局部對象),那麼RAAII機制會工作正常,當對象生命周期結束時會調用其析構函數來釋放資源。但是當對象是在堆上創建時(用new操作符),那麼要想析構該對象內存就需要調用delete操作符了。這這方式存在隱患,當我們new了之後忘了delete就會造成內存洩露。

(二)智能指針

  boost.smart_ptr庫提供了六種智能指針,包括:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr和intrusive_ptr。在使用這些智能指針時,需要模板類型T的析構函數不能拋出異常。

  要使用這些智能指針,需要在加入加入文件:

#include <boost/smart_ptr.hpp>
//using namespace boost;

(1)scoped_ptr

  scoped_ptr包裝了new操作符在堆上分配的動態對象,它有嚴格的所有權,即它包裝的對象指針不能轉讓,一旦scoped_ptr獲取了對象的管理權,就無法從它那裡取回來。就像它的取名一樣,這個智能指針只能在本作用域裡使用,不希望被轉讓。

  來看下scoped_ptr的源代碼:

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;
}

#include <boost/smart_ptr/detail/operator_bool.hpp>

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

  可以看到scoped_ptr把復制構造函數和賦值操作符(=)都聲明為私有的,這樣保證了scoped_ptr的noncopyable,也保證了其管理的指針不能被轉讓。還要注意scoped_ptr無法比較,因為它的兩個重載比較運算符是私有的。

  注意:由於scoped_ptr不能拷貝和賦值,所以它不能作為容器的元素。

(2)scoped_array

  scoped_array很像scoped_ptr,它包裝的是new []和delete []操作。

  下面是scoped_ptr的部分源代碼:

template<class T> class scoped_array // noncopyable{
private:
T * px;
scoped_array(scoped_array const &);
scoped_array & operator=(scoped_array const &);

typedef scoped_array<T> this_type;

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

public:
typedef T element_type;

explicit scoped_array( T * p = 0 ) BOOST_NOEXCEPT : px( p ) {
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_array_constructor_hook( px );
#endif
}

~scoped_array() // never throws {
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_array_destructor_hook( px );
#endif
boost::checked_array_delete( px );
}

void reset(T * p = 0) // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) {
BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
this_type(p).swap(*this);
}

T & operator[](std::ptrdiff_t i) const // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) {
BOOST_ASSERT( px != 0 );
BOOST_ASSERT( i >= 0 );
return px[i];
}

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

#include <boost/smart_ptr/detail/operator_bool.hpp>

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

  注意:
•構造函數接收的是new []的結果
•沒有重載*和->操作符;
•提供了operator[]操作符的重載,可以像普通數組一樣使用;
•沒有begin()、end()迭代器。

  建議:scoped_ptr的使用還是有些不靈活,首先它值提供了一個指針的形式,所有在需要使用數組的時候還是使用std::vector容器代替scoped_ptr比較好。

(3)shared_ptr

  shared_ptr也是包裝了new操作符,但是它最重要的一點是它實現了引用計數,所以它可以被自由的拷貝和賦值,跟其名字一樣是可以共享的,當沒有代碼使用(即引用計數為0)時,它才刪除被包裝的動態分配的對象內存。可被當做容器的元素。

  以下是它的部分源代碼:

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

public:
typedef typename boost::detail::sp_element< T >::type element_type;

shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() {}
template<class Y> explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete
{boost::detail::sp_pointer_construct( this, p, pn );}

template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d )
{boost::detail::sp_deleter_construct( this, p );}

// As above, but with allocator. A's copy constructor shall not throw.
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a )
{ boost::detail::sp_deleter_construct( this, p );}

template<class Y>
explicit shared_ptr( weak_ptr<Y> const & r ): pn( r.pn ) // may throw{
boost::detail::sp_assert_convertible< Y, T >();
// it is now safe to copy r.px, as pn(r.pn) did not throw
px = r.px;
}

template<class Y>
shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag )
BOOST_NOEXCEPT : px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag()){
if( !pn.empty() ){
px = r.px;
}
}

template<class Y>
shared_ptr( shared_ptr<Y> const & r )

BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
{boost::detail::sp_assert_convertible< Y, T >();}

template< class Y >
shared_ptr( shared_ptr<Y> const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ) {}

template< class Y, class D >
shared_ptr( boost::movelib::unique_ptr< Y, D > r ): px( r.get() ), pn(){
boost::detail::sp_assert_convertible< Y, T >();
typename boost::movelib::unique_ptr< Y, D >::pointer tmp = r.get();
pn = boost::detail::shared_count( r );
boost::detail::sp_deleter_construct( this, tmp );
}

shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT
{ this_type(r).swap(*this); return *this; }


template<class Y, class D>
shared_ptr & operator=( boost::movelib::unique_ptr<Y, D> r ) {
boost::detail::sp_assert_convertible< Y, T >();
typename boost::movelib::unique_ptr< Y, D >::pointer p = r.get();
shared_ptr tmp;
tmp.px = p;
tmp.pn = boost::detail::shared_count( r );
boost::detail::sp_deleter_construct( &tmp, p );
tmp.swap( *this );
return *this;
}

void reset() BOOST_NOEXCEPT // never throws in 1.30+
{this_type().swap(*this);}

template<class Y> void reset( Y * p ) // Y must be complete {
BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
this_type( p ).swap( *this );
}

template<class Y, class D> void reset( Y * p, D d )
{ this_type( p, d ).swap( *this ); }

template<class Y, class D, class A> void reset( Y * p, D d, A a )
{this_type( p, d, a ).swap( *this );}

template<class Y> void reset( shared_ptr<Y> const & r, element_type * p )
{ this_type( r, p ).swap( *this );}

// never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const{
BOOST_ASSERT( px != 0 );
BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) );
return static_cast< typename boost::detail::sp_array_access< T >::type >( px[ i ] );
}

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

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

bool unique() const BOOST_NOEXCEPT
{ return pn.unique();}

long use_count() const BOOST_NOEXCEPT
{return pn.use_count();}

void swap( shared_ptr & other ) BOOST_NOEXCEPT
{std::swap(px, other.px); pn.swap(other.pn);}

private:
template<class Y> friend class shared_ptr;
template<class Y> friend class weak_ptr;

#endif
element_type * px; // contained pointer
boost::detail::shared_count pn; // reference counter
};

  不能使用static_cast<T *>(sp.get())這種形式將shared_ptr管理的指針進行顯示轉換,而shared_ptr也提供了static_pointer_cast<T>()、const_pointer_cast<T>()和dynamic_pointer_cast<T>()幾個對應的成員函數。另外應使用unique(),不適用use_count()==1的形式。

  另外在創建shared_ptr的時候可以使用工廠函數來創建(make_shared<T>()),它位於文件make_shared.hpp中。使用時需要:

#include <boost/make_shared.hpp>
  這是make_shared其中一個實現方式:

template< class T, class... Args > typename boost::detail::sp_if_not_array< T >::type make_shared( Args && ... args )
{
boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );

boost::detail::sp_ms_deleter< T > * pd = static_cast<boost::detail::sp_ms_deleter< T > *>( pt._internal_get_untyped_deleter() );

void * pv = pd->address();

::new( pv ) T( boost::detail::sp_forward<Args>( args )... );
pd->set_initialized();

T * pt2 = static_cast< T* >( pv );

boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
return boost::shared_ptr< T >( pt, pt2 );
}

  注意:關於shared_ptr還有很多知識點。。。

(4)weak_ptr

  weak_ptr是為配合shared_ptr而引入的一種智能指針,不具有普通指針的行為,它沒有重載operator *和->操作符。用於觀測share_ptr中所管理的資源的使用情況。

template<class T> class weak_ptr
{
private:
// Borland 5.5.1 specific workarounds
typedef weak_ptr<T> this_type;

public:
typedef typename boost::detail::sp_element< T >::type element_type;

weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+{}

// generated copy constructor, assignment, destructor are fine...

#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )

// ... except in C++0x, move disables the implicit copy
weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ){}

weak_ptr & operator=( weak_ptr const & r ) BOOST_NOEXCEPT{
px = r.px;
pn = r.pn;
return *this;
}

#endif

template<class Y>
#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )
weak_ptr( weak_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
#else
weak_ptr( weak_ptr<Y> const & r )
#endif
BOOST_NOEXCEPT : px(r.lock().get()), pn(r.pn){ boost::detail::sp_assert_convertible< Y, T >(); }
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y>
#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )
weak_ptr( weak_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
#else
weak_ptr( weak_ptr<Y> && r )
#endif
BOOST_NOEXCEPT : px( r.lock().get() ), pn( static_cast< boost::detail::weak_count && >( r.pn ) ){
boost::detail::sp_assert_convertible< Y, T >();
r.px = 0;
}

// for better efficiency in the T == Y case
weak_ptr( weak_ptr && r )
BOOST_NOEXCEPT : px( r.px ), pn( static_cast< boost::detail::weak_count && >( r.pn ) ){ r.px = 0; }

// for better efficiency in the T == Y case
weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT{
this_type( static_cast< weak_ptr && >( r ) ).swap( *this );
return *this;
}

#endif
template<class Y>
#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )
weak_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
#else
weak_ptr( shared_ptr<Y> const & r )
#endif
BOOST_NOEXCEPT : px( r.px ), pn( r.pn ){
boost::detail::sp_assert_convertible< Y, T >();
}
#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)
template<class Y>
weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT{
boost::detail::sp_assert_convertible< Y, T >();
px = r.lock().get();
pn = r.pn;
return *this;
}
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y>
weak_ptr & operator=( weak_ptr<Y> && r ) BOOST_NOEXCEPT{
this_type( static_cast< weak_ptr<Y> && >( r ) ).swap( *this );
return *this;
}
#endif
template<class Y>
weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT{
boost::detail::sp_assert_convertible< Y, T >();
px = r.px;
pn = r.pn;
return *this;
}
#endif

shared_ptr<T> lock() const BOOST_NOEXCEPT{
return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );
}

long use_count() const BOOST_NOEXCEPT{ return pn.use_count(); }

bool expired() const BOOST_NOEXCEPT{ return pn.use_count() == 0; }

bool _empty() const // extension, not in std::weak_ptr{ return pn.empty(); }

void reset() BOOST_NOEXCEPT // never throws in 1.30+{ this_type().swap(*this); }

void swap(this_type & other) BOOST_NOEXCEPT{
std::swap(px, other.px);
pn.swap(other.pn);
}

template<typename Y>
void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2){ px = px2; pn = r.pn; }

template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT{ return pn < rhs.pn; }

template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT{ return pn < rhs.pn; }

// Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston)
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
template<class Y> friend class weak_ptr;
template<class Y> friend class shared_ptr;
#endif

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

  weak_ptr被設計為與shared_ptr共同工作的,可以從一個shared_ptr或者另一個weak_ptr對象構造,獲取資源的觀測權。但weak_ptr沒有共享資源,它的構造不會引起指針引用計數的增加。同樣,在weak_ptr析構時也不會導致引用計數的減少。

  使用weak_ptr的成員函數use_count()可以獲取shared_ptr的引用計數,另一個expired()的功能等價於use_count()==0,但是更快,表示被觀測的資源已經不存在。

  獲得this的shared_ptr:

  在文件<boost/enable_shared_from_this.hpp>中定義了一個enable_shared_from_this<T>類,它的聲明摘要:

template<class T> class enable_shared_from_this{
protected:
enable_shared_from_this() BOOST_NOEXCEPT{ }
enable_shared_from_this(enable_shared_from_this const &) BOOST_NOEXCEPT { }
enable_shared_from_this & operator=(enable_shared_from_this const &) BOOST_NOEXCEPT { return *this; }
~enable_shared_from_this() BOOST_NOEXCEPT { }
public:
shared_ptr<T> shared_from_this() {
shared_ptr<T> p( weak_this_ );
BOOST_ASSERT( p.get() == this );
return p;
}

shared_ptr<T const> shared_from_this() const{
shared_ptr<T const> p( weak_this_ );
BOOST_ASSERT( p.get() == this );
return p;
}

weak_ptr<T> weak_from_this() BOOST_NOEXCEPT { return weak_this_; }
weak_ptr<T const> weak_from_this() const BOOST_NOEXCEPT { return weak_this_; }

public: // actually private, but avoids compiler template friendship issues
// Note: invoked automatically by shared_ptr; do not call
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const{
if( weak_this_.expired() ){
weak_this_ = shared_ptr<T>( *ppx, py );
}
}

private:
mutable weak_ptr<T> weak_this_;
};

  在使用的時候只需要讓想被shared_ptr管理的類繼承自enable_shared_from_this,調用成員函數shared_form_this()會返回this的shared_ptr。例如:

#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <iostream>

class self_shared : public boost::enable_shared_from_this<self_shared>{
public:
self_shared(int n) : x(n) { }
int x;

void print(){
std::cout<<"self_shared:"<<x<<std::endl;
}
};

int main(int argc,char * argv[]){
std::shared_ptr<self_shared> sp=std::make_shared<self_shared>(123);
sp->print();
std::shared_ptr<self_shared> p=sp->shared_from_this();
p->x=100;
p->print();
return 0;
}

要注意的是:千萬不能從一個普通的對象(self_shared對象)使用shared_from_this()獲取shared_ptr,例如:

self_shared ss;
boost::shared_ptr<self_shared> p=ss.shared_from_this();

這個在程序運行時會導致shared_ptr析構時企圖刪除一個在棧上分配的對象,發生未定義行為。

Ubuntu下編譯安裝boost庫 http://www.linuxidc.com/Linux/2013-07/87573.htm

Ubuntu下編譯boost 1.52b http://www.linuxidc.com/Linux/2013-02/79004.htm

VS2008下直接安裝使用Boost庫1.46.1版本 http://www.linuxidc.com/Linux/2014-08/105253.htm

Ubuntu編譯安裝boost並在eclipse C/C++中使用 http://www.linuxidc.com/Linux/2011-04/34790.htm

Boost 的詳細介紹:請點這裡
Boost 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved