国外流量统计

Boost库学习(3) 内存管理

 preface:

  1、传统C++内存管理中可能出现的问题:内存泄露、野指针、访问越界;相关解决方案:智能指针 std::auto_ptr,不能完全解决内存管理中出现的问题;

  2、关于smart_ptr库的概述:

    2.1、C++程序员通常采用RAII(资源获取即初始化)机制管理内存资源,在使用资源的类的构造函数中申请资源,最后在析构函数中释放资源;如果对象的声明方式是在栈上,RAII机制可以工作正常,但是如果对象是用new操作符在堆上创建的,那么它的析构函数不会自动的调用,需要手动delete,然而即便是C++熟手,也很容易忘记;

    2.2、智能指针实践了代理模式,代理了原始的“裸”指针行为,为它添加了许多有用的特性;

    2.3、auto_ptr很好用,但是没有覆盖智能指针的全部领域,尤其是引用计数型的智能指针;boost.smart_ptr库是对C++98的一个绝佳补充,它提供了六种智能指针:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr、intrusive_ptr,库中的两个类shared_ptr和weak_ptr已经加入到C++的新标准中TR1库中。

    2.4、这些智能指针都位于名字空间boost,为了使用smart_ptr组件,需要包含头文件:

    #include"boost\smart_ptr.hpp"

    using namespace boost;

 

一、scoped_ptr

  1、简介:类似于auto_ptr,包装了new在堆上分配的动态对象,保证动态创建的对象在任何时候都可以正确的被删除,但是scoped_ptr的所有权更加严格,不能转让,一旦scoped_ptr取得对象的管理权,就无法从它哪里取回来了;

  2、类摘要:

View Code
 1 template<class T>
 2 class scoped_ptr
 3 {
 4 private:
 5     T* px;
 6     scoped_ptr(scoped_ptr const &);
 7     scoped_ptr& operator=(scoped_ptr const&);
 8 public:
 9     explicit scoped_ptr(T* p = 0);
10     ~scoped_ptr();
11     void reset(T* p=0);
12 
13     T& operator*() const;
14     T* operator->() const;
15     T* get() const;
16 
17     operator unspecified-bool-type() const;
18     void swap(scoped_ptr &b);
19 };

 

  说明:<a>拷贝构造函数和赋值函数都是私有,保证其不被复制,保证了被他管理的指针的所有权不被转让;

     <b>scoped_ptr不支持比较的操作,它已经将operator==和operator!=两个操作符号的重载声明为私有了;但是其提供了可以再bool语境中自动转换成bool值的功能,用来测试scoped_ptr是否持有一个有效的指针(非空),它可以代替和空指针的比较操作。

  3、用法:在原本使用指针变量接收new表达式结果的地方改成用scoped_ptr对象,然后去掉那些多余的try/catch和delete操作就可以了。

  备注:与auto_ptr的区别和联系

    scoped_ptr的用法和auto的几乎一样,大多数的情况下,可以和auto_ptr互换,也可以从auto_ptr获取指针的管理权(同时auto_ptr失去管理权);scoped_ptr也具有auto_ptr同样的缺陷---不能用作容器元素,但是原因不同,auto_ptr是因为它的转移语意,而scoped_ptr则是因为不支持拷贝和赋值,不符号容器对元素的要求。scoped_ptr与auto_ptr根本性的区别在于指针的所有权,auto_ptr特意被设计为指针的所有权是可转移的,可以在函数之间传递,而同一时刻只能有一个auto_ptr管理指针,而scoped_ptr把拷贝构造函数和赋值函数都声明为私有,拒绝了指针所有权的转让,除了scoped_ptr自己,其他任何人都无权访问被管理的指针,从而保证了指针的绝对安全。

 

二、scoped_array

  1、简介:包装了new[]操作符在堆上分配的动态数组,为动态数组提供了代理,保证可以正确释放内存。scoped_array弥补了标准库中没有指向数组的智能指针的缺憾。

  2、类摘要:

View Code
 1 template<class T>
 2 class scoped_array
 3 {
 4 public:
 5     explicit scoped_array(T* p=0);
 6     ~scoped_array();
 7 
 8     void reset(T* p = 0);
 9     T& operator[](std::ptrdiff_t i) const;
10     T* get() const;
11 
12     operator unspecifid-bool-type() const;
13     void swap(scoped_array& b);
14 };

   备注:

    <a>构造函数接受的指针p必须是new[]的结果

    <b>没有*,->的操作符重载,因为scoped_array持有的不是一个普通的指针;

    <c>析构函数使用delete[]释放资源,而不是delete;

    <d>提供operator[]操作符重载,可以像普通数组一样用下标访问元素;

    <e>没有begin(),end()等类似容器的迭代器操作的函数;

  3、用法:

    3.1、scoped_array重载了operator[],因此它用起来就像是一个普通的数组,但是它不提供指针运算,所以不能用“数组首地址+N”的方式访问数组元素;

    3.2、使用重载的operaor[]时要小心,scoped_array不提供数组索引范围检查;

  使用建议:

    scoped_array的功能很限,不能动态增长,也没有迭代器支持,不能搭配STL算法,仅有一个“裸”数组接口。在需要动态数组的情况下,我们应该使用std::vector,它比scoped_array提供了更多了灵活性。

 

三、shared_ptr

  1、简介:是boost.smart_ptr库中最有价值、最重要的组成部分,也是最有用的。shared_ptr和scoped_ptr一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以自由的拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它才删除动态分配的对象,share_ptr也可以安全的放到标准容器中,

  2、类摘要:

 View Code
 1 template<class T>
 2 class shared_ptr
 3 {
 4 public:
 5     typedef T element_type;
 6 
 7     shared_ptr();
 8     template<class Y> explicit shared_ptr(Y* p);
 9     template<class Y,class D>shared_ptr(Y*p,D d);
10     ~shared_ptr();
11 
12     shared_ptr(shared_ptr const& r);
13     template<class Y> explicit shared_ptr(std::auto_ptr<Y>& r);
14 
15     shared_ptr& operator=(shared_ptr const& r);
16     template<class Y> shared_ptr& operator=(shared_ptr<Y> const& r);
17     template<class Y> shared_ptr& operator=(std::auto_ptr<Y> const& r);
18 
19     void reset();
20     template<class Y> void reset(Y* p);
21     template<class Y,class D>void rest(Y* p,D d);
22 
23     T& operator*() const;
24     T* operator->() const;
25     T* get() const;
26 
27     bool unique() const;
28     long use_count() const;
29 
30     operator unspecified-bool-type() const;
31     void swap(shared_ptr& b);
32 };

  备注:shared_ptr提供多种形式的构造函数

    <a>无参share_ptr()创建一个持有空指针的shared_ptr;

    <b>shared_ptr(Y* p)获得指向类型T的指针p的管理权,同时引用计数置1,这个构造要求类型必须能够转化为T类型;

    <c>shared_ptr(std::auto_ptr<Y>& r)从一个auto_ptr获得指针的管理权,引用计数置1,同时auto_ptr自动失去管理权;

    <d>operator=赋值符可以从另外一个shared_ptr或auto_ptr获得指针管理权,其行为同构造函数;

    <e>shared_ptr(Y* p,D d)行为类似于shared_ptr(Y* p),但使用参数d指定了析构时的定制删除器,而不是简单的delete。

    对于引用计数的问题:

    <a>shared_ptr的reset函数与scoped_ptr的不尽相同,它的作用是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则类似相同形式的构造函数,原指针引用计数减1的同时改为管理另一指针。

    <b>shared_ptr有两个函数来检查引用计数,unique()在shared_ptr是指针的唯一所有者时返回true,use_count()返回当前指针的引用计数。

    关于“比较”运算

    <a>shared_ptr支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get()==b.get()。shared_ptr还可以用operator<比较大小,同样基于内部保存的指针,但不提供除operator<意外的比较操作符,这使得shared_ptr可以用于标准关联容器(set和map);

    关于“类型转换”

    在编写基于虚函数的多态代码时指针的类型转换很有用,但对于shared_ptr不能使用static_case<T*>(p.get())的形式,这将导致转型后的指针无法再不被shared_ptr正确管理,为了支持这样的用法,shared_ptr提供了类似的转型函数:static_pointer_case<T>()、const_pointer_case<T>()和dynamic_pointer_case<T>(),他们与标准的static_case<T>、const_case<T>和dynamic_case<T>类似,但返回的是转型后的shared_ptr.

  3、用法

    3.1 工厂函数(消除new和delete出现的不对称性)  

View Code
 1 #include "stdafx.h"
 2 #include<iostream>
 3 #include<map>
 4 #include<memory>
 5 #include<vector>
 6 #include<cassert>
 7 using namespace std;
 8 
 9 #include "boost\smart_ptr.hpp"
10 #include "boost\make_shared.hpp"
11 
12 int _tmain(int argc, _TCHAR* argv[])
13 {
14     shared_ptr<string> sp = make_shared<string>("make_shared");
15     shared_ptr< vector<int> > spv = make_shared< vector<int> >(10,2);
16     assert(spv->size() == 10);
17     return 0;
18 }

    说明:

    <a>shared_ptr在头文件<boost/make_shared.hpp>中提供了一个自由工厂函数,make_shared<T>来消除显示new的调用,make_shared的函数可以接受最多10个参数,然后把它们传递给类型T的构造函数,创建一个shared_ptr<T>对象然后返回。make_shared函数要比直接创建shared_ptr对象快且高效,内部仅分配一次内存,来消除shared_ptr构造开销;

    3.2 应用于标准容器

View Code
 1 #include "stdafx.h"
 2 #include<iostream>
 3 #include<map>
 4 #include<memory>
 5 #include<vector>
 6 #include<cassert>
 7 using namespace std;
 8 

 9 #include "boost\smart_ptr.hpp"
10 #include "boost\make_shared.hpp"
11 
12 int _tmain(int argc, _TCHAR* argv[])
13 {
14     typedef vector< shared_ptr<int> > vs;
15     vs v(10);
16 
17     int i = 0;
18     for(vs::iterator pos =v.begin();pos != v.end();++pos)
19     {
20         (*pos) = make_shared<int>(++i);
21         cout<<*(*pos)<<", ";
22     }
23     cout<<endl;
24 
25     shared_ptr<int> p = v[9];
26     *p = 100;
27     cout<<*v[9]<<endl;
28 
29     return 0;
30 }

    说明:

    <a>有两种方式可以将shared_ptr应用于标准容器(或者容器适配器等其他容器)

      一种是:将容器作为shared_ptr管理的对象,如shared_ptr< list<T> >,使容器可以被安全地共享;

      另一种是:将shared_ptr作为容器元素,如vector< shared_ptr<T> >,因为shared_ptr支持拷贝语义和比较操作,符合标准容器对元素的要求,可以实现在容器中安全的容纳元素的指针而不是拷贝。

    <b>标准容器不能容纳auto_ptr和scoped_ptr,标准容器可以容纳原始指针,但这就散失了容器的许多好处,因为标准容器无法自动管理类型为指针的元素,必须编写额外的大量的代码来保证指针最终被正确删除,这通常很麻烦且难实现。存储shared_ptr的容器与存储原始指针的容器功能几乎一样,但shared_ptr为程序员做了指针的管理工作,可以任意使用shared_ptr而不用担心资源泄露。

    3.3 应用于桥接模式

View Code
 1 class sample
 2 {
 3 private:
 4     class impl;                    
 5     shared_ptr<impl> p;
 6 public:
 7     sample();
 8     void print():
 9 };
10 
11 class sample::impl
12 {
13 public:
14     void print()
15     {
16         cout<<"impl print"<<endl;
17     }
18 };
19 
20 sample::sample():p(new impl){}
21 void sample::print()
22 {
23     p->print();
24 }
25 
26 sample s;
27 s.print();

     说明:

    <a>先声明一个类sample,它仅向外界暴露了最小的细节,真正的实现在内部类impl,sample用了一个shared_ptr来保存它的指针;

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

    <c>scoped_ptr和shared_ptr都可以用来实现桥接模式,但shared_ptr更合适,因为它支持拷贝和赋值,这在很多情况下都是有用的,比如说:配合容器工作。

    3.4 应用于工厂模式

View Code
 1 #include "stdafx.h"
 2 #include<iostream>
 3 #include<map>
 4 #include<memory>
 5 #include<vector>
 6 #include<cassert>
 7 using namespace std;
 8 
 9 #include "boost\smart_ptr.hpp"
10 #include "boost\make_shared.hpp"
11 
12 class abstract
13 {
14 public :
15     virtual void f()=0;
16     virtual void g()=0;
17 protected:
18     virtual ~abstract(){}
19 };
20 
21 class impl:public abstract
22 {
23 public:
24     virtual void f()
25     {
26         cout<<"class impl f"<<endl;
27     }
28 
29     virtual void g()
30     {
31         cout<<"class impl g"<<endl;
32     }
33 };
34 
35 shared_ptr<abstract> create()
36 {
37     return shared_ptr<abstract>(new impl);
38 }
39 
40 
41 int _tmain(int argc, _TCHAR* argv[])
42 {
43     shared_ptr<abstract> p = create();
44     p->f();
45     p->g();
46     return 0;
47 }

    说明:

    <a>工厂模式是一种创建型的设计模式,包装了new操作符号的使用,使对象的创建工作集中在工厂类或者工厂函数中,从而更容易适应变化,make_shared()就是工厂模式的一个很好的例子;

    <b>C++不能高效的返回一个对象,在程序中编写自己的工厂类或工厂函数通常需要在堆上使用new动态分配一个对象,然后返回对象的指针,这种做法不安全,用户容易忘记调用delete,使用shared_ptr就可以解决这个问题;

    3.5 定制删除器

View Code
class socket_t{...};

socket_t* open_socket()
{
    cout<<"open_socket"<<endl;
    return new socket_t;
}

void close_socket(socket_t* s)
{
    cout<<"close_socket"<<endl;
    //。。。其他操作,释放资源
}


socket_t * s = open_socket();
shared_ptr<socket_t> p(s,close_socket);

     说明:

     <a>这样我们就使用shared_ptr配合定制的删除器管理了socket资源,但离开作用域时,shared_ptr会自动调用close_socket()函数关闭socket,再也不会有资源遗失的担心;

     <b>shared_ptr的删除器在处理某些资源时非常有用,它使得用户可以定制、拓展shared_ptr的行为,使得shared_ptr不仅仅能够管理内存资源,而是成为一个"万能"的资源管工具;

     <c>shared_ptr(Y* p,D d)的第一个参数是要被管理的指针,第二个参数d则告诉shared_ptr在析构时不是使用delete的操作指针p,而是要用d来操作,即把delete p换成d(p);

     <d>这里删除器d可以是一个函数对象,也可以是一个函数指针,只要它能够像函数那样被调用,使得d(p)成立即可。对删除器的要求是它必须是可拷贝的,行为必须也像delete那样,不能抛出异常。shared_ptr提供了一个自由函数get_deleter(shared_ptr<T> const & p),它能够返回函数指针;

    3.6 高级议题

      3.6.1 shared_ptr<void>能够存储void*型指针,就像一个泛型的指针容器,拥有容纳任意类型的能力,但是将指针存储为void*将丧失原来的类型信息,为了需要的时候正确调用,可以用static_pointer_cast<T>等转型函数重新转为原来的指针,涉及到运行时类型的动态转换,使得代码不安全,不建议使用;

      3.6.2 shared_ptr<void>可以实现在退出作用域时调用任意函数。

View Code
 1 void any_func(void* p)
 2 {
 3     cout<<"some operate"<<endl;
 4 }
 5 
 6 int main()
 7 {
 8     shared_ptr<void> p((void*)0,any_func);
 9     return 0;
10 }

 

四、shared_array

  1、简介:shared_array类似shared_ptr,它包装了new[]操作符在堆上分配的动态数组,同样适用引用计数机制为动态数组提供一个代理,可以在程序的生命周期里长期存在,直到没有任何引用才释放内存。

  2、类摘要:

View Code
 1 template<class T>
 2 class shared_array
 3 {
 4 public:
 5     explicit shared_array(T* p = 0);
 6     template<class D>shared_array(T* p,D d);
 7     ~shared_array();
 8 
 9     shared_array(shared_array const& r);
10 
11     shared_array& operator=(shared_array const& r);
12 
13     void reset(T* p = 0);
14     template<class D> void reset(T* p,D d);
15     
16     T& operator[](std::ptrdiff_t i) const() const;
17     T* get() const;
18 
19     bool unique() const;
20     long use_count() const;
21 
22     void swap(shared_array<T>& b);
23 };

  备注:

  <a>构造函数接受指针p必须是new[]的结果,而不能是new表达式的结果;

  <b>提供operator[]操作符的重载,可以像普通数组一样用下标访问元素;

  <c>没有*,->操作符重载,因为shared_ptr持有的不是一个普通指针;

  <d>析构函数使用delete[]释放资源,而不是delete。

   3、用法

  在使用shared_array重载的operator[]时要小心,shared_array不提供数组索引的范围检查,如果使用了超过动态数组大小的索引将引发可怕的未定义行为。shared_array能力有限,多数情况下它可以用shared_ptr<std::vector>或者std::vector<shared_ptr>来代替,这两个方案具有更好的安全性和更多的灵活性,而所付出的的代价几乎可以忽略不计。

 

五、weak_ptr

  1、简介:weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->。它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

  2、类摘要

View Code
 1 template<class T>
 2 class weak_ptr
 3 {
 4 public:
 5     weak_ptr();
 6     template<class Y>weak_ptr(shared_ptr<Y> const& r);
 7     weak_ptr(weak_ptr const& r);
 8 
 9     ~weak_ptr();
10 
11     weak_ptr& operator=(weak_ptr const& r);
12 
13     long use_count() const;
14 
15     bool expired() const;
16 
17     shared_ptr<T> lock() const;
18 
19     void reset();
20 
21     void swap(weak_ptr<T>& b);
22 };

   3、用法

    <a>weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但是weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数减少。

    <b>使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count() ==0,但更快,表示被观测的资源(也就是shared_ptr管理的资源)已经不复存在;

   <c>weak_ptr没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这正是它"弱"的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。但当expired() == true的时候,lock()函数返回一个存储空指针的shared_ptr。

View Code
 1 shared_ptr<int> sp(new int(10));
 2 assert(sp.use_count() == 1);
 3 
 4 weak_ptr<int> wp(sp);                    //从shared_ptr创建weak_ptr
 5 assert(wp.use_count() == 1)                //weak_ptr不影响引用计数
 6 
 7 if(!wp.expired())                        //判断weak_ptr观察的对象是否失效
 8 {    
 9     shared_ptr<int> sp2 = wp.lock();    //获得一个shared_ptr
10     *sp2 = 100;
11     assert(wp.use_count() == 2);
12 }                                        //退出作用域,sp2自动析构,引用计数减1
13 
14 assert(wp.use_count() == 1);
15 sp.reset();                                    //shared_ptr失效
16 assert(wp.expired());
17 assert(!wp.lock());                            //weak_ptr将获得一个空指针

    <d>获得this的shared_ptr

       说明:weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己;对象使用weak_ptr观测this指针,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr供外界使用。这个解决方案被实现为一个惯用法,在头文件<boost/enable_from_this.hpp>定义一个助手类enable_shared_this<T>,它的声明摘要如下:

View Code
1 template<class T>
2 class enable_shared_from_this
3 {
4     public:
5         enable_shared_from_this();
6 };

      使用的时候只需要让相被shared_ptr管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr。

View Code
 1 #include <boost/enable_shared_from_this.hpp>
 2 #include <boost/make_shared.hpp>
 3 
 4 class self_shared:public enable_shared_from_this<self_shared>
 5 {
 6 public:
 7     self_shared(int n):x(n){}
 8     int x;
 9     void print()
10     {
11         cout<<"self_shared:"<<x<<endl;
12     }
13 };
14 
15 int main()
16 {
17     shared_ptr<self_shared> sp = make_shared<self_shared>(314);
18     sp->print();
19     shared_ptr<self_shared> p = sp->shared_from_this();
20     p->x = 1000;
21     p->print();
22 }

      备注:千万不能从一个普通对象(非shared_ptr)使用shared_from_this()获取shared_ptr

 

六、instrusive_ptr

   1、简介:是一个侵入式的引用计数型指针,不推荐使用。

 

七、pool库

  1、简述:boost.pool库基于简单分隔存储思想实现了一个快速、紧凑的内存池库,不仅能够管理大量的对象,还可以被用作STL的内存分配器。从某种程度上讲,它近似于一个小型的垃圾回收机制,在需要大量地分配/释放小对象时很有效率,而且完全不需要考虑delete。pool库包含是个组成部分:最简单的pool,分配类实例的object_pool、单件内存池singleton_pool和可以用于标准库的pool_alloc。

  2、pool

    2.1、简介:最简单也最容易使用的内存池类,可以返回简单类型数据的内存指针。

    2.2、类摘要

View Code
 1 template<typename UserAllocator=...>
 2 class pool
 3 {
 4     public:
 5         explicit pool(size_type requested_size);
 6         ~pool();
 7         size_type get_requested_size() const;
 8 
 9         void* malloc();
10         void* ordered_malloc();
11         void* ordered_malloc(size_type n);
12         bool is_from(void* chunk) const;
13 
14         void free(void * chunk);
15         void ordered_free(void* chunk);
16         void free(void* chunks,size_type n);
17         void ordered_free(void* chunks,size_type n);
18 
19         bool release_memory();
20         bool purge_memory();
21 
22 };

        说明:

        <a>pool模板类型参数UserAllocator是一个用户定义的内存分配器,它实现了特定的内存分配算法,通常可以直接用默认的default_user_allocator_new_delete。

        <b>pool的构造函数接受一个size_type类型的整数requested_size,指示每次pool分配内存块的大小(而不是pool内存池的大小),这个值可以用get_requested_size()获得。pool会根据需要自动地向系统申请或归还使用的内存,在析构,pool将自动释放它所持有所有内存块。

         <c>成员函数malloc()和order_malloc()的行为很类似C中的全局函数malloc(),用void*指针返回从内存池中分配的内存块,大小为构造函数中指定的requested_size。如果内存分配失败,函数会返回0,不会抛出异常。malloc()从内存池中任意分配一个内存块,而order_malloc()则在分配的同时合并空闲块链表。order_malloc()带参数的形式还可以连续分配n块的内存。分配后的内存块可以用is_from()函数测试是否从这个内存池分配出去的。

         <d>与malloc()对应的一组函数是free(),用来手工释放之前分配的内存块,这些内存块必须是从这个内存池分配出去的(is_from(chunk) == true),一般情况内存池会自动管理内存分配,不应该调用free()函数,除非你认为内存池的空间不足,必须释放已经分配的内存。

        <e>release_memory()让内存池释放所有未被分配的内存,但已分配的内存块不受影响:purge_memory()则强制释放pool持有的所有内存,不管内存块是否被使用。实际上,pool的析构函数就是调用purge_memory()。这个函数一般情况下也不应该由程序员手工调用。

    2.3 用法

View Code
 1 #include <boost/pool/pool.hpp>
 2 using namespace boost;
 3 
 4 int main()
 5 {
 6     pool<> pl(sizeof(int));
 7 
 8     int* p = (int*)p1.malloc();
 9     assert(p1.is_from(p));
10 
11     p1.free(p);
12     for(int i-0;i<100;i++)
13     {
14         p1.order_malloc(10);
15     }
16 }

    备注:

      <a>pool分配内存失败不会抛出异常,实际编写的代码应该检查malloc()函数返回的指针,防止空指针错误。

      <b>它只能作为普通数据类型如int、double等的内存池,不能应用于复杂的类和对象,因为它只分配内存,不调用构造函数,这个时候我们需要用object_pool。

  3、object_pool

    3.1 简介:用于类实例(对象)的内存池,会在析构时对所有已经分配的内存块调用析构函数。需包含头文件:#include<boost/pool/object_pool.hpp> using namspace boost;

    3.2 类摘要

View Code
 1 template<typename ElementType>
 2 class object_pool:protected pool
 3 {
 4 public:
 5     object_pool();
 6     ~object_pool();
 7 
 8     element_type* malloc();
 9     void free(element_type* p);
10     bool is_from(element_type* p) const;
11 
12     element_type* construct(...);
13     void destroy(element_type* p);
14 };

     备注:

      <a>object_pool要分配的元素类型,要求其析构函数不能抛出异常,一旦在模板中指定了类型,object_pool实例就不再用于分配其他类型的对象。

      <b>object_pool特殊之处是construct()和destroy()函数,construct()实际上是一组函数,有多个函数的重载形式,它先调用malloc()分配内存,然后再在内存块上使用传入的参数调用类的构造函数,返回的是一个已经初始化的对象指针。destroy()则先调用对象的析构函数,然后再用free()释放内存块。这些函数都不会抛出异常,如果内存分配失败,将返回0;

     3.3 用法

View Code
 1 #include<boost/pool/object_pool.hpp>
 2 using namespace boost;
 3 
 4 struct demo_class
 5 {
 6 public:
 7     int a,b,c;
 8     demo_class(int x = 1,int y  =2,int z = 3):a(x),b(y),c(z){}
 9 };
10 
11 int main()
12 {
13     object_pool<demo_class> p1;        //对象内存池
14 
15     demo_class* p = p1.malloc();    //分配一个原始内存块
16     assert(p1.if_from(p));
17 
18     
19     //p指向的内存未经过初始化
20     assert(p->a != 1 || p->b != 2 || p->c != 3);
21 
22     //构造一个对象,可以传递参数
23     p = p1.construct(7,8,9);
24     assert(p->a == 7);
25 
26     //定义一个分配string对象的内存池
27     object_pool<string> pls;
28     //连续大量分配string对象
29     for (int i=0;i<10;++i)
30     {
31         string* ps = pls.construct("hello object_pool");
32         cout<<*ps<<endl;
33     }
34     
35     return 0;
36 }

    备注:默认情况下,在使用object_pool的construct()的时候我们最多用三个参数来创建对象,但construct被设计为可拓展的,它基于宏处理m4实现了一个拓展机制,可以自动生成接收任意数量参数的construct函数。

  4、singleton_pool

     4.1、简介:singleton_pool与pool的接口完全一致,可以分配简单数据类型(POD)的内存指针,但它是一个单件,并提供线程安全。目前boost还未提供标准的单件库,singleton_pool在其内部实现了一个较简单、泛型的单间类,保证main()函数运行之前就创建单件。需包含一下头文件:#include<boost/pool/singleton_pool.hpp> using namespace boost;

     4.2、类摘要

View Code
 1 template<typename Tag,unsigned RequestedSize>
 2 class singleton_pool
 3 {
 4 public:
 5     static bool is_from(void* ptr);
 6     static void* malloc();
 7     static void* ordered_malloc();
 8     static void* ordered_malloc(size_type n);
 9 
10     static void free(void* ptr);
11     static void ordered_free(void* ptr);
12     static void free(void* ptr,std::size_t n);
13     static void ordered_free(void* ptr,size_type n);
14 
15     static bool release_memory();
16     static bool purge_memory();
17 };

     备注:

     <a>singleton_pool主要是有两个摸板类型参数(其余的可以使用缺省值)。第一个Tag用于标记不同的单件,可以是空类,甚至是声明。第二个参数RequestedSize等同于pool构造函数中的整数requested_size,指示pool分配内存块的大小。

     <b>singleton_pool接口与pool完全一致,但函数均是静态的,因此不需要声明singleton_pool的实例,直接用域操作符::来调用静态成员函数。因为singleton_pool是单件,所以它的生命周期与整个程序同样长,除非手动调用release_memory()或purge_memory(),否则singleton_pool不会自动释放所占用的内存。除了这两点,singleton_pool的用法与pool完全相同。

     4.3 用法

View Code
 1 #include <boost/pool/singleton_pool>
 2 using namespace boost;
 3 
 4 struct pool tag{};
 5 
 6 typedef singleton_pool<pool_tag,sizeof(int)> sp1;
 7 
 8 int main()
 9 {
10     int * p = (int*)sp1::malloc();
11     assert(sp1::is_from(p));
12     sp1::release_memory();
13 
14     return 0;
15 }

 

  5、pool_alloc

    5.1 简介:pool_alloc提供了两个可以用于标准容器模板参数的内存分配器,分别是pool_alloc()和fast_pool_allocator,它们的行为与之前的内存池类有一点不同---当内存分配失败时会抛出异常std::bad_alloc。它们位于名字空间boost,需要包含头文<boost/pool/pool_alloc.hpp>。除非有特殊的需求,我们应该总使用STL实现自带的内存分配器,使用pool_alloc需要经过仔细测试,以保证它和容器可以共同工作。

    5.2 用法

View Code
1 #include <boost/pool/pool_alloc.hpp>
2 using namespace boost;
3 
4 int main()
5 {
6     vector< int,pool_allocator<int> > v;    //使用pool_allocator代替标准容器默认的内存分配器
7     v.push_back(10);                        //vector将使用新的分配器良好工作
8     cout<v.size();
9 }

 

 

 

 

 

    

posted @ 2013-04-16 13:40  蓝海骇客  阅读(618)  评论(0编辑  收藏  举报
无觅关联推荐,快速提升流量