文章目录

  • 三、内存管理库
    • 3.1 smart_ptr
      • 3.1.1 RAII机制
      • 3.1.2 智能指针
      • 3.1.3 scoped_ptr
      • 3.1.4 scoped_array
      • 3.1.5 shared_ptr
      • 3.1.6 weak_ptr
    • 3.2 pool
    • 3.3 object_pool

三、内存管理库

3.1 smart_ptr

3.1.1 RAII机制

​ 为了管理内存资源,c++程序员经常采用RAII机制(资源获取即初始化),在使用资源的构造函数内申请资源,然后使用,最后在析构时释放资源。

​ 在栈空间上申请的空间会在生命周期结束后自动调用析构,但是如果是new的对象则不会自动调用析构函数,只能在使用delete后才会释放空间,这里就存在内存泄漏的风险,如果意外导致delete语句未执行,将会产生不小的麻烦,这个内存将永久丢失了。

3.1.2 智能指针

​ 智能指针会在退出作用域时候,不论正常流程离开还是异常流程离开,总会调用delete来释放资源。

​ smart_ptr库是对c++98的完美补充,其下有六种常见类型指针:

  • scoped_ptr:
  • scoped_array:
  • shared_ptr:
  • shared_array:
  • weak_ptr:
  • intrusive_ptr:

3.1.3 scoped_ptr

​ 这是一个很类似于auto_ptr的指针,其所有权更加严格,不能转让,一旦其获取了对象的管理权,则无法从它那里取回对象的管理权(类似于unique_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 ) BOOST_SP_NOEXCEPT : px( p ){
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_constructor_hook( px );
    #endif}#ifndef BOOST_NO_AUTO_PTRexplicit scoped_ptr( std::auto_ptr<T> p ) BOOST_SP_NOEXCEPT : px( p.release() ){
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_constructor_hook( px );
    #endif}#endif~scoped_ptr() BOOST_SP_NOEXCEPT{
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_destructor_hook( px );
    #endifboost::checked_delete( px );}void reset(T * p = 0) BOOST_SP_NOEXCEPT_WITH_ASSERT{BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errorsthis_type(p).swap(*this);}T & operator*() const BOOST_SP_NOEXCEPT_WITH_ASSERT{BOOST_ASSERT( px != 0 );return *px;}T * operator->() const BOOST_SP_NOEXCEPT_WITH_ASSERT{BOOST_ASSERT( px != 0 );return px;}T * get() const BOOST_SP_NOEXCEPT{return px;}// implicit conversion to "bool"
    #include <boost/smart_ptr/detail/operator_bool.hpp>void swap(scoped_ptr & b) BOOST_SP_NOEXCEPT{T * tmp = b.px;b.px = px;px = tmp;}
    };
  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <string>using namespace std;
    using namespace boost;int main()
    {scoped_ptr<string> sp(new string("text"));cout << *sp<<endl; //内容cout << sp->size()<<endl;//实际字节数//scoped_ptr源码中将赋值和拷贝构造设置成了私有成员,即不能够进行拷贝和赋值//除了*和->外,其没有重载其他的运算符,所以也不能进行++或者--操作sp++;//错误的使用:未定义++操作符scoped_ptr<string> sp2=sp;//错误的使用:隐式调用拷贝构造函数,因为私有所以不允许这样做return 0;
    }
    
  • 和auto_ptr的区别:

    使用上几乎一样,auto_ptr允许转移代理,但是代理只能有一个(一旦通过赋值转移代理后,原auto_ptr对象将会失去管理权),可以用于函数传参,这个用意是好的,但是这个过程很危险。而scoped_ptr私有了拷贝构造和赋值,所以直接不允许这样做。

3.1.4 scoped_array

​ 内部封装了new [],即弥补了标准库中没有可以指向数组的智能指针的缺陷。

​ 比scoped_ptr多的是提供了[]的重载运算符,可以正常使用下标索引访问对象中的元素

  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <string>
    #include <cstring>
    using namespace std;
    using namespace boost;int main()
    {scoped_array<int> sa(new int[10]);//memset(sa.get(),0,sizeof (int)*10);//get()方法得到该对象的指针。fill_n(sa.get(),10,5);//也可以使用memsetfor(int i=0;i<10;i++){cout<<sa[i]<<endl;}return 0;
    }
    

3.1.5 shared_ptr

​ shared_ptr 是一个最想指针的“智能指针”,是boost.smart_ptr中最具有价值的一个,也是最有用的。有着非常高的利用价值。

​ shared_ptr和scoped_ptr一样,封装了new操作符在堆上分配动态对象,但是它实现的是引用计数的只能指针。可以自由的进行拷贝和赋值,任意地方都可以共享它,当没有代码使用它时才会释放被包装的动态分配的对象。shared_ptr也可以安全的放到STL的标准容器中去,弥补了auto_ptr因为语义转移而不能放进容器中的缺陷。

​ shared_ptr也提供基本的线程安全保证,一个shared_ptr可以被多个线程安全读取,但其他的访问形式结果是未定义的。

  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <string>
    #include <cstring>
    using namespace std;
    using namespace boost;int main()
    {boost::shared_ptr<int> sp(new int (0));assert(sp);assert(sp.unique());*sp = 23;boost::shared_ptr<int> sp2 = sp;assert(sp==sp2 && sp.use_count()==2);*sp2 = 100;assert(*sp2==100);cout<<*sp<<"   "<<*sp2<<endl;sp.reset();assert(!sp);cout<<sp<<endl;//sp为空指针boost::shared_ptr<string> sps(new string("smart"));assert(sps->size()==5);return 0;
    }
    
  • shared_ptr下的自由工厂函数:

    用来弥补不对称性(只new不delete),因为shared_ptr中封装了new操作符,但是过多调用也会有过多的new操作符的问题,所以才有了工厂函数。

    该函数在<make_shared.hpp>中定义,声明在boost命名空间中,函数原型如下:

    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 );
    }
    • 案例:

      #include <iostream>
      #include <boost/smart_ptr.hpp>
      #include <boost/make_shared.hpp>//自用工厂函数的头文件
      #include <string>
      #include <cstring>
      #include <vector>using namespace std;
      using namespace boost;int main()
      {boost::shared_ptr<string> sp = boost::make_shared<string>("make shared");
      boost::shared_ptr<vector<int> > spv = boost::make_shared<vector<int> >(10, 2);return 0;
      }
      
    • 除了make_shared(),smart_ptr还提供一个allocate_shared()函数,使用方法和上边一样,只是多了一个内存分配器参数。

  • 应用于标准容器:存放标准指针的标准容器一般在资源释放的时候会有很多麻烦的问题,所以可以使用shared_ptr存放于标准容器中(shared_ptr支持拷贝和赋值,而auto_ptr 和 scoped_ptr不支持这样做。

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <boost/make_shared.hpp>//自用工厂函数的头文件
    #include <string>
    #include <cstring>
    #include <vector>using namespace std;
    using namespace boost;int main()
    {typedef vector<boost::shared_ptr<int> > vs;vs v(10); // 10个元素的vectorint i = 0;for (vs::iterator it=v.begin();it!=v.end();++it) {(*it) = boost::make_shared<int>(++i); // 避免了new int(++i);让代码更加对称cout<< *(*it) <<",";}cout<<endl;boost::shared_ptr<int> p = v[9];(*p) = 100;cout << *(v[9])<<endl;return 0;
    }
    
  • 应用于桥接模式:

    桥接模式是一种结构型设计模式,其把类的具体实现模式对用户隐藏起来,已达到类之间最小耦合关系。桥接模式也被称之为pimpl或者handle/body惯用法。它可以将头文件的依赖关系降到最低,减小编译事件,而且可以不使用虚函数实现多态。

    桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过==提供抽象化和实现化之间的桥接结构,来实现二者的解耦==。

    通常用相同的抽象方法但是不同的桥接实现类,来实现不同的实现功能。

    桥接模式的意图:实现抽象部分和实现部分的分离。

    • 桥接模式的实现:

      我们有一个作为桥接实现的 DrawAPI 接口实现了 DrawAPI 接口的实体类 RedCircleGreenCircleShape是一个抽象类,将使用 DrawAPI 的对象BridgePatternDemo 类使用 Shape 类来画出不同颜色的圆

  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <boost/make_shared.hpp>//自用工厂函数的头文件
    #include <string>
    #include <cstring>
    #include <vector>using namespace std;
    using namespace boost;class sample{
    private:class impl;boost::shared_ptr<impl> p;
    public:sample();void print();
    };class sample::impl{
    public:void print(){cout<<"impl print"<<endl;}
    };sample::sample():p(new impl){}//不用管理impl的内部释放了
    void sample::print(){p->print();}int main()
    {sample sm;sm.print();return 0;
    }
    

3.1.6 weak_ptr

​ 是为了配合shared_ptr而产生的一种智能指针,但是其没有重载->和*运算符,所以其不具备指针的能力。其最大的作用是协助shared_ptr,成为一个旁观者观察资源的使用情况。

​ weak_ptr被设计和shared_ptr一起工作,可以从一个shared_ptr或者weak_ptr构造得到,获得资源的观测权,它的构造不会引起引用计数的增加。其中的use_count()函数可以观测引用个数,另一个成员函数expired()功能等价于use_count()==0,引用计数为0(没有指针指向资源或者资源被释放)时返回true,但是更快,表示被观测的资源不复存在。它可以通过lock()函数获得一个可用的shared_ptr对象,从而操作资源,当expired()==true时,lock()函数将返回一个存储空指针的shared_ptr对象。

  • 原型:

    template<class T> class weak_ptr
    {
    private:// Borland 5.5.1 specific workaroundstypedef weak_ptr<T> this_type;public:typedef typename boost::detail::sp_element< T >::type element_type;BOOST_CONSTEXPR weak_ptr() BOOST_SP_NOEXCEPT : px(0), pn(){}//  generated copy constructor, assignment, destructor are fine...#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )// ... except in C++0x, move disables the implicit copyweak_ptr( weak_ptr const & r ) BOOST_SP_NOEXCEPT : px( r.px ), pn( r.pn ){}weak_ptr & operator=( weak_ptr const & r ) BOOST_SP_NOEXCEPT{px = r.px;pn = r.pn;return *this;}#endif//
    //  The "obvious" converting constructor implementation:
    //
    //  template<class Y>
    //  weak_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn)
    //  {
    //  }
    //
    //  has a serious problem.
    //
    //  r.px may already have been invalidated. The px(r.px)
    //  conversion may require access to *r.px (virtual inheritance).
    //
    //  It is not possible to avoid spurious access violations since
    //  in multithreaded programs r.px may be invalidated at any point.
    //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() )#elseweak_ptr( weak_ptr<Y> const & r )#endifBOOST_SP_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() )#elseweak_ptr( weak_ptr<Y> && r )#endifBOOST_SP_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 caseweak_ptr( weak_ptr && r )BOOST_SP_NOEXCEPT : px( r.px ), pn( static_cast< boost::detail::weak_count && >( r.pn ) ){r.px = 0;}// for better efficiency in the T == Y caseweak_ptr & operator=( weak_ptr && r ) BOOST_SP_NOEXCEPT{this_type( static_cast< weak_ptr && >( r ) ).swap( *this );return *this;}#endiftemplate<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() )#elseweak_ptr( shared_ptr<Y> const & r )#endifBOOST_SP_NOEXCEPT : px( r.px ), pn( r.pn ){boost::detail::sp_assert_convertible< Y, T >();}// aliasingtemplate<class Y> weak_ptr(shared_ptr<Y> const & r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( r.pn ){}template<class Y> weak_ptr(weak_ptr<Y> const & r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( r.pn ){}#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )template<class Y> weak_ptr(weak_ptr<Y> && r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( std::move( r.pn ) ){}#endif#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)template<class Y>weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_SP_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_SP_NOEXCEPT{this_type( static_cast< weak_ptr<Y> && >( r ) ).swap( *this );return *this;}#endiftemplate<class Y>weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_SP_NOEXCEPT{boost::detail::sp_assert_convertible< Y, T >();px = r.px;pn = r.pn;return *this;}#endifshared_ptr<T> lock() const BOOST_SP_NOEXCEPT{return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );}long use_count() const BOOST_SP_NOEXCEPT{return pn.use_count();}bool expired() const BOOST_SP_NOEXCEPT{return pn.use_count() == 0;}bool _empty() const BOOST_SP_NOEXCEPT // extension, not in std::weak_ptr{return pn.empty();}bool empty() const BOOST_SP_NOEXCEPT // extension, not in std::weak_ptr{return pn.empty();}void reset() BOOST_SP_NOEXCEPT{this_type().swap(*this);}void swap(this_type & other) BOOST_SP_NOEXCEPT{std::swap(px, other.px);pn.swap(other.pn);}template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_SP_NOEXCEPT{return pn < rhs.pn;}template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_SP_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_FRIENDSprivate:template<class Y> friend class weak_ptr;template<class Y> friend class shared_ptr;#endifelement_type * px;            // contained pointerboost::detail::weak_count pn; // reference counter};
    
  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <boost/make_shared.hpp>//自用工厂函数的头文件
    #include <string>
    #include <cstring>
    #include <vector>using namespace std;
    using namespace boost;int main()
    {boost::shared_ptr<int> p = boost::make_shared<int>(10);assert(p.use_count()==1);boost::weak_ptr<int> wp(p);assert(wp.use_count()==1);if(!wp.expired()){//当资源未被释放时boost::shared_ptr<int> sp = wp.lock();*sp = 100;assert(wp.use_count()==2);}assert(wp.use_count()==1);p.reset();assert(wp.expired());//有资源时报错assert(!wp.lock());//非空指针报错return 0;
    }
    

3.2 pool

​ 内存池:预先分配一块很大的内存,通过某些算法实现高效的自定制内存分配。

​ pool是最简单最有用的内存池类,可以返回一个简单数据类型POD的内存指针。

  • 原型:

    template <typename UserAllocator>
    class pool: protected simple_segregated_storage < typename UserAllocator::size_type >
    {public:typedef UserAllocator user_allocator; //!< User allocator.typedef typename UserAllocator::size_type size_type;  //!< An unsigned integral type that can represent the size of the largest object to be allocated.typedef typename UserAllocator::difference_type difference_type;  //!< A signed integral type that can represent the difference of any two pointers.private:BOOST_STATIC_CONSTANT(size_type, min_alloc_size =(::boost::integer::static_lcm<sizeof(void *), sizeof(size_type)>::value) );BOOST_STATIC_CONSTANT(size_type, min_align =(::boost::integer::static_lcm< ::boost::alignment_of<void *>::value, ::boost::alignment_of<size_type>::value>::value) );//! \returns 0 if out-of-memory.//! Called if malloc/ordered_malloc needs to resize the free list.void * malloc_need_resize(); //! Called if malloc needs to resize the free list.void * ordered_malloc_need_resize();  //! Called if ordered_malloc needs to resize the free list.protected:details::PODptr<size_type> list; //!< List structure holding ordered blocks.simple_segregated_storage<size_type> & store(){ //! \returns pointer to store.return *this;}const simple_segregated_storage<size_type> & store() const{ //! \returns pointer to store.return *this;}const size_type requested_size;size_type next_size;size_type start_size;size_type max_size;//! finds which POD in the list 'chunk' was allocated from.details::PODptr<size_type> find_POD(void * const chunk) const;// is_from() tests a chunk to determine if it belongs in a block.static bool is_from(void * const chunk, char * const i,const size_type sizeof_i){ //! \param chunk chunk to check if is from this pool.//! \param i memory chunk at i with element sizeof_i.//! \param sizeof_i element size (size of the chunk area of that block, not the total size of that block).//! \returns true if chunk was allocated or may be returned.//! as the result of a future allocation.//!//! Returns false if chunk was allocated from some other pool,//! or may be returned as the result of a future allocation from some other pool.//! Otherwise, the return value is meaningless.//!//! Note that this function may not be used to reliably test random pointer values.// We use std::less_equal and std::less to test 'chunk'//  against the array bounds because standard operators//  may return unspecified results.// This is to ensure portability.  The operators < <= > >= are only//  defined for pointers to objects that are 1) in the same array, or//  2) subobjects of the same object [5.9/2].// The functor objects guarantee a total order for any pointer [20.3.3/8]std::less_equal<void *> lt_eq;std::less<void *> lt;return (lt_eq(i, chunk) && lt(chunk, i + sizeof_i));}size_type alloc_size() const{ //!  Calculated size of the memory chunks that will be allocated by this Pool.//! \returns allocated size.// For alignment reasons, this used to be defined to be lcm(requested_size, sizeof(void *), sizeof(size_type)),// but is now more parsimonious: just rounding up to the minimum required alignment of our housekeeping data// when required.  This works provided all alignments are powers of two.size_type s = (std::max)(requested_size, min_alloc_size);size_type rem = s % min_align;if(rem)s += min_align - rem;BOOST_ASSERT(s >= min_alloc_size);BOOST_ASSERT(s % min_align == 0);return s;}static void * & nextof(void * const ptr){ //! \returns Pointer dereferenced.//! (Provided and used for the sake of code readability :)return *(static_cast<void **>(ptr));}public:// pre: npartition_size != 0 && nnext_size != 0explicit pool(const size_type nrequested_size,const size_type nnext_size = 32,const size_type nmax_size = 0):list(0, 0), requested_size(nrequested_size), next_size(nnext_size), start_size(nnext_size),max_size(nmax_size){ //!   Constructs a new empty Pool that can be used to allocate chunks of size RequestedSize.//! \param nrequested_size  Requested chunk size//! \param  nnext_size parameter is of type size_type,//!   is the number of chunks to request from the system//!   the first time that object needs to allocate system memory.//!   The default is 32. This parameter may not be 0.//! \param nmax_size is the maximum number of chunks to allocate in one block.}~pool(){ //!   Destructs the Pool, freeing its list of memory blocks.purge_memory();}// Releases memory blocks that don't have chunks allocated// pre: lists are ordered//  Returns true if memory was actually deallocatedbool release_memory();// Releases *all* memory blocks, even if chunks are still allocated//  Returns true if memory was actually deallocatedbool purge_memory();size_type get_next_size() const{ //! Number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be 0.//! \returns next_size;return next_size;}void set_next_size(const size_type nnext_size){ //! Set number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be set to 0.//! \returns nnext_size.next_size = start_size = nnext_size;}size_type get_max_size() const{ //! \returns max_size.return max_size;}void set_max_size(const size_type nmax_size){ //! Set max_size.max_size = nmax_size;}size_type get_requested_size() const{ //!   \returns the requested size passed into the constructor.//! (This value will not change during the lifetime of a Pool object).return requested_size;}// Both malloc and ordered_malloc do a quick inlined check first for any//  free chunks.  Only if we need to get another memory block do we call//  the non-inlined *_need_resize() functions.// Returns 0 if out-of-memoryvoid * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(){ //! Allocates a chunk of memory. Searches in the list of memory blocks//! for a block that has a free chunk, and returns that free chunk if found.//! Otherwise, creates a new memory block, adds its free list to pool's free list,//! \returns a free chunk from that block.//! If a new memory block cannot be allocated, returns 0. Amortized O(1).// Look for a non-empty storageif (!store().empty())return (store().malloc)();return malloc_need_resize();}void * ordered_malloc(){ //! Same as malloc, only merges the free lists, to preserve order. Amortized O(1).//! \returns a free chunk from that block.//! If a new memory block cannot be allocated, returns 0. Amortized O(1).// Look for a non-empty storageif (!store().empty())return (store().malloc)();return ordered_malloc_need_resize();}// Returns 0 if out-of-memory// Allocate a contiguous section of n chunksvoid * ordered_malloc(size_type n);//! Same as malloc, only allocates enough contiguous chunks to cover n * requested_size bytes. Amortized O(n).//! \returns a free chunk from that block.//! If a new memory block cannot be allocated, returns 0. Amortized O(1).// pre: 'chunk' must have been previously//        returned by *this.malloc().void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk){ //!   Deallocates a chunk of memory. Note that chunk may not be 0. O(1).//!//! Chunk must have been previously returned by t.malloc() or t.ordered_malloc().//! Assumes that chunk actually refers to a block of chunks//! spanning n * partition_sz bytes.//! deallocates each chunk in that block.//! Note that chunk may not be 0. O(n).(store().free)(chunk);}// pre: 'chunk' must have been previously//        returned by *this.malloc().void ordered_free(void * const chunk){ //! Same as above, but is order-preserving.//!//! Note that chunk may not be 0. O(N) with respect to the size of the free list.//! chunk must have been previously returned by t.malloc() or t.ordered_malloc().store().ordered_free(chunk);}// pre: 'chunk' must have been previously//        returned by *this.malloc(n).void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunks, const size_type n){ //! Assumes that chunk actually refers to a block of chunks.//!//! chunk must have been previously returned by t.ordered_malloc(n)//! spanning n * partition_sz bytes.//! Deallocates each chunk in that block.//! Note that chunk may not be 0. O(n).const size_type partition_size = alloc_size();const size_type total_req_size = n * requested_size;const size_type num_chunks = total_req_size / partition_size +((total_req_size % partition_size) ? true : false);store().free_n(chunks, num_chunks, partition_size);}// pre: 'chunk' must have been previously//        returned by *this.malloc(n).void ordered_free(void * const chunks, const size_type n){ //! Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes;//! deallocates each chunk in that block.//!//! Note that chunk may not be 0. Order-preserving. O(N + n) where N is the size of the free list.//! chunk must have been previously returned by t.malloc() or t.ordered_malloc().const size_type partition_size = alloc_size();const size_type total_req_size = n * requested_size;const size_type num_chunks = total_req_size / partition_size +((total_req_size % partition_size) ? true : false);store().ordered_free_n(chunks, num_chunks, partition_size);}// is_from() tests a chunk to determine if it was allocated from *thisbool is_from(void * const chunk) const{ //! \returns Returns true if chunk was allocated from u or//! may be returned as the result of a future allocation from u.//! Returns false if chunk was allocated from some other pool or//! may be returned as the result of a future allocation from some other pool.//! Otherwise, the return value is meaningless.//! Note that this function may not be used to reliably test random pointer values.return (find_POD(chunk).valid());}
    };
    
  • 案例:

    #include <iostream>
    #include <boost/pool/pool.hpp>using namespace std;
    using namespace boost;int main()
    {pool<> p(sizeof(int));//整型字节的空间//<>是因为采用默认模板int* p1 = (int*)p.malloc();//malloc函数分配内存失败后会返回空指针,一般返回void*if(!p1){cout<<"error!"<<endl;}else{cout<<p.get_requested_size()<<endl;}assert(p.is_from(p1));//p1是否是p所申请的内存指针p.free(p1);//释放p1for(int i=0;i<10;i++){p.ordered_malloc(10);//连续申请10字节空间}return 0;//内存池对象析构,所有空间被释放
    }
    
    • 注意:pool只能申请简单类型的空间,不能生成复杂类型的空间,因为其只申请空间,并不会调用构造函数。如果要分配复杂类型的空间,要是用object_pool();

3.3 object_pool

​ object_pool是pool的受保护继承的子类,因此外界无法使用pool的接口,而object_pool的特殊之处在于construct()函数和destroy()函数,是其价值所在。construct()实际上是一组函数,有三种重载形式,它先调用malloc分配空间,然后再通过参数调用类的构造函数,返回一个已经初始化的对象的指针。而destroy用于先调用对象的析构函数,再调用free()释放内存。

  • 原型:

    template <typename T, typename UserAllocator>
    class object_pool: protected pool<UserAllocator>
    { //!public:typedef T element_type; //!< ElementTypetypedef UserAllocator user_allocator; //!<typedef typename pool<UserAllocator>::size_type size_type; //!<   pool<UserAllocator>::size_typetypedef typename pool<UserAllocator>::difference_type difference_type; //!< pool<UserAllocator>::difference_typeprotected://! \return The underlying boost:: \ref pool storage used by *this.pool<UserAllocator> & store(){ return *this;}//! \return The underlying boost:: \ref pool storage used by *this.const pool<UserAllocator> & store() const{ return *this;}// for the sake of code readability :)static void * & nextof(void * const ptr){ //! \returns The next memory block after ptr (for the sake of code readability :)return *(static_cast<void **>(ptr));}public:explicit object_pool(const size_type arg_next_size = 32, const size_type arg_max_size = 0):pool<UserAllocator>(sizeof(T), arg_next_size, arg_max_size){ //! Constructs a new (empty by default) ObjectPool.//! \param next_size Number of chunks to request from the system the next time that object needs to allocate system memory (default 32).//! \pre next_size != 0.//! \param max_size Maximum number of chunks to ever request from the system - this puts a cap on the doubling algorithm//! used by the underlying pool.}~object_pool();// Returns 0 if out-of-memory.element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(){ //! Allocates memory that can hold one object of type ElementType.//!//! If out of memory, returns 0. //!//! Amortized O(1).return static_cast<element_type *>(store().ordered_malloc());}void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk){ //! De-Allocates memory that holds a chunk of type ElementType.//!//!  Note that p may not be 0.\n//!//! Note that the destructor for p is not called. O(N).store().ordered_free(chunk);}bool is_from(element_type * const chunk) const{ /*! \returns true  if chunk was allocated from *this ormay be returned as the result of a future allocation from *this.Returns false if chunk was allocated from some other pool ormay be returned as the result of a future allocation from some other pool.Otherwise, the return value is meaningless.\note This function may NOT be used to reliably test random pointer values!*/return store().is_from(chunk);}element_type * construct(){ //! \returns A pointer to an object of type T, allocated in memory from the underlying pool//! and default constructed.  The returned objected can be freed by a call to \ref destroy.//! Otherwise the returned object will be automatically destroyed when *this is destroyed.element_type * const ret = (malloc)();if (ret == 0)return ret;try { new (ret) element_type(); }catch (...) { (free)(ret); throw; }return ret;}#if defined(BOOST_DOXYGEN)template <class Arg1, ... class ArgN>element_type * construct(Arg1&, ... ArgN&){//! \returns A pointer to an object of type T, allocated in memory from the underlying pool//! and constructed from arguments Arg1 to ArgN.  The returned objected can be freed by a call to \ref destroy.//! Otherwise the returned object will be automatically destroyed when *this is destroyed.//!//! \note Since the number and type of arguments to this function is totally arbitrary, a simple system has been //! set up to automatically generate template construct functions. This system is based on the macro preprocessor //! m4, which is standard on UNIX systems and also available for Win32 systems.\n\n//! detail/pool_construct.m4, when run with m4, will create the file detail/pool_construct.ipp, which only defines //! the construct functions for the proper number of arguments. The number of arguments may be passed into the //! file as an m4 macro, NumberOfArguments; if not provided, it will default to 3.\n\n//! For each different number of arguments (1 to NumberOfArguments), a template function is generated. There //! are the same number of template parameters as there are arguments, and each argument's type is a reference //! to that (possibly cv-qualified) template argument. Each possible permutation of the cv-qualifications is also generated.\n\n//! Because each permutation is generated for each possible number of arguments, the included file size grows //! exponentially in terms of the number of constructor arguments, not linearly. For the sake of rational //! compile times, only use as many arguments as you need.\n\n//! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments //! to be their command-line parameter. See these files for more details.}
    #else
    // Include automatically-generated file for family of template construct() functions.
    // Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11.
    // But still get Doxygen warning:
    // I:/boost-sandbox/guild/pool/boost/pool/object_pool.hpp:82:
    // Warning: include file boost/pool/detail/pool_construct.ipp
    // not found, perhaps you forgot to add its directory to INCLUDE_PATH?
    // But the file IS found and referenced OK, but cannot view code.
    // This seems because not at the head of the file
    // But if moved this up, Doxygen is happy, but of course it won't compile,
    // because the many constructors *must* go here.#ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
    #   include <boost/pool/detail/pool_construct.ipp>
    #else
    #   include <boost/pool/detail/pool_construct_simple.ipp>
    #endif
    #endifvoid destroy(element_type * const chunk){ //! Destroys an object allocated with \ref construct. //!//! Equivalent to://!//! p->~ElementType(); this->free(p);//!//! \pre p must have been previously allocated from *this via a call to \ref construct.chunk->~T();(free)(chunk);}size_type get_next_size() const{ //! \returns The number of chunks that will be allocated next time we run out of memory.return store().get_next_size();}void set_next_size(const size_type x){ //! Set a new number of chunks to allocate the next time we run out of memory.//! \param x wanted next_size (must not be zero).store().set_next_size(x);}
    };
    
  • 案例:

    #include <iostream>
    #include <boost/smart_ptr.hpp>
    #include <boost/make_shared.hpp>//自用工厂函数的头文件
    #include <boost/pool/pool.hpp>
    #include <boost/pool/object_pool.hpp>
    #include <string>
    #include <cstring>
    #include <vector>using namespace std;
    using namespace boost;struct demo_class{int a,b,c;demo_class(int x=1,int y=2,int z=3):a(x),b(y),c(z){}
    };int main()
    {object_pool<demo_class> p1;demo_class* p = p1.malloc();assert(p1.is_from(p));assert(p->a!=1 || p->b!=2 || p->c!=3);//p所指向的空间并没有初始化std::cout<<"未初始化的三个值:"<< p->a <<" "<< p->b <<" "<< p->c<<std::endl;p = p1.construct();//调用demo_class的构造函数,采用默认值进行初始化。(x==1,y==2,z==3)assert(p->a==1 || p->b==2 || p->c==3);//p所指的空间被初始化cout<< p->a << p->b << p->c<<endl;return 0;//内存池对象析构,所有空间被释放
    }
    

C++大法:举世闻名之BOOST大法精华浅析(三)内存管理库(小白piao分享)相关推荐

  1. 浅析java内存管理机制

    内存管理是计算机编程中的一个重要问题,一般来说,内存管理主要包括内存分配和内存回收两个部分.不同的编程语言有不同的内存管理机制,本文在对比C++和java语言内存管理机制的不同的基础上,浅析java中 ...

  2. 【Boost】系列03:内存管理之shared_ptr智能指针

    最有价值的!最有用的引用计数型智能指针,可以被拷贝和赋值,可以作为STL容器的元素: 1,基本用法: #include <boost/smart_ptr.hpp> #include < ...

  3. 【Boost】系列02:内存管理之scoped_ptr智能指针

    智能指针,stl中有auto_ptr,boost的smart_ptr库有6种: scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr和int ...

  4. 浅析linux内存管理

    物理内存和虚拟内存 现代的操作系统中进程访问的都是虚拟内存,而虚拟内存到物理内存的转换是由系统默默完成的.首先来扒一扒它的历史,直接使用物理内存效率岂不是更高,何必加一个中间层? 在计算机早期,物理内 ...

  5. Boost ASIO proactor 浅析

    Boost ASIO proactor 浅析 前情提要: Boost asio 的socket的异步非阻塞模式才有的是proactor模式,当IO操作介绍后回调相应的处理函数.ASIO在Linux平台 ...

  6. mysql 线程缓存_浅析MySQL内存的使用说明(全局缓存+线程缓存)

    首先我们来看一个公式,MySQL中内存分为全局内存和线程内存两大部分(其实并不全部,只是影响比较大的 部分): 复制代码 代码如下: per_thread_buffers=(read_buffer_s ...

  7. java内存模型浅析_浅析java内存模型

    原标题:浅析java内存模型 Java内存模型规范了Java虚拟机与计算机内存是如何协同工作的.Java虚拟机是一个完整的计算机的一个模型,因此这个模型自然也包含一个内存模型--又称为Java内存模型 ...

  8. boost::random模块实现如何使用随机数库的简短演示程序

    boost::random模块实现如何使用随机数库的简短演示程序 实现功能 C++实现代码 实现功能 boost::random模块实现如何使用随机数库的简短演示程序 C++实现代码 #include ...

  9. boost::math模块使用二项分布复制 NAG 库调用的测试程序

    boost::math模块使用二项分布复制 NAG 库调用的测试程序 实现功能 C++实现代码 实现功能 boost::math模块使用二项分布复制 NAG 库调用的测试程序 C++实现代码 #inc ...

最新文章

  1. (笔记) (ARM) QQ2440 开发板改为 GT2440 (Linux) (开发板)
  2. 【高级绘图】MATLAB应用实战系列(八十)-圣诞前夜,想表白女神?教你如何用MATLAB绘制圣诞树动态图(附MATLAB代码)
  3. pl/sql里的exists和in的差别
  4. docker镜像了解(建立私有仓库,基于已有镜像创建,Docker的数据管理) 基于Dockerfile创建,基于本地模板创建,端口映射,容器互联)
  5. Linux学习总结(14)——Linux权限控制
  6. python-day11 Mysql 数据类型
  7. 联想e52进入bios_联想昭阳E52-80笔记本win10怎么改win7
  8. Phoenix命令及语法
  9. 世界上最成熟、功能最全的加密库HELib
  10. 此版本的visual studio无法打开下列项目_深度学习实现高精度钢琴曲转谱Piano transcription项目简明使用教程...
  11. 每日一JAVA----------环境搭建Path,JAVA_HOME,classpath
  12. Android开发:申请小米开发者账号步骤
  13. 如何改变win10鼠标样式
  14. java excel 日期格式转换_Java处理Excel中的日期格式
  15. Java批量解析微信dat文件,微信图片破解
  16. git提交失败running pre-commit hook: lint-staged [33m‼ Some of your tasks use `git add` command
  17. 输入一个字符,是小写转换为大写,大写转换为小写,其他字符原样输出
  18. 使用turtle库,绘制一个正方形。
  19. 深入理解MyBatis(七)—MyBatis事务
  20. 在Devil的软件三角中管理成功; 项目,项目经理和开发人员

热门文章

  1. 关于营销自动化,30个惊人的事实
  2. 保研英语自我介绍计算机,计算机保研面试英文自我介绍
  3. 笔记本电脑禁用集显会变卡?
  4. 基于SSM大学生宿舍交电费系统
  5. 借助MATLAB与SIMULINK仿真嵌入式C算法
  6. Flyme应用中心应用认领
  7. check if DVE variable is valid
  8. ANSYS预紧力螺栓连接结构(—HyperMesh添加预压力单元)
  9. 电脑开不了机系统应该如何恢复正常
  10. 无限地球危机的观看顺序