Boost 内存管理(smart_ptr库,pool库)

来源:互联网 发布:ubuntu安装哪个版本好 编辑:程序博客网 时间:2024/05/16 11:45

1. RAII机制

为了管理内存等资源,C++程序员通常采用RAII机制(资源获取即初始化,Resource Acquisition Is Initialization),在使用资源的类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。
1. 在栈上创建对象(局部对象):RAII机制正常工作,当离开作用域时,对象会自动销毁从而调用析构函数释放资源
2. 在堆上创建对象,使用new操作符,那么它的析构函数不会自动调用,只有对应的delete操作符销毁它才能释放资源。

2. 智能指针

STL中收录: #include <memory>
1. shared_ptr 允许多个指针指向同一个对象
2. unique_ptr 独占所指向的对象
3. weak_ptr 指向shared_ptr所指管理的对象,不控制对象生命周期。

2.1 shared_ptr, 工厂函数

引用计数型的智能指针,可以被自由的拷贝和赋值,在任意地方共享它,当没有代码使用(引用计数为0)时才删除被包装的动态分配的对象。
shared_ptr 很好的消除了显示的delete调用,完全可以不再使用delete。

//shared_ptr<int> sp(new int(10));  //一个指向整数的shared_ptrshared_ptr<int> sp2=sp;  //拷贝//较复杂的用法void print_func(shared_ptr<int> p){    //do something    cout<<p.use_count()<<endl;  //引用计数}//函数接受shared_ptr对象作为参数,特别注意的是,并没有使用引用的方式传递参数,而是直接拷贝,就像在使用原始指针,引用计数+1

最安全的分配和使用动态内存的方法是调用make_shared的标准库函数(工厂函数)

#include <memory>shared_ptr<int> sp=make_shared<int>(10);

2.2 unique_ptr

某个时刻只能有一个unique_ptr指向一个给定对象,unique_ptr拥有它所指的对象,因此unique_ptr不支持普通的拷贝或赋值操作

#include <memory>unique_ptr<int> up(new int(43));  //直接初始化

2.3 weak_ptr

weak_ptr 指向shared_ptr所指管理的对象,不控制对象生命周期。
不具有普通指针的行为,没有重载operator* 和 -> ,这是特意的,因为它不共享指针,不能操作资源,这是它“弱”的原因。
但它可以使用成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。
最大的作用是协助shared_ptr工作,像旁观者那样观测资源的使用情况。

用法:

#include <memory>shared_ptr<int> sp(new int(43));weak_ptr<int> wp(sp);if(!wp.expired()){    shared_ptr<int> sp2=wp.lock();  //sp引用计数+1    *sp2=100;}//退出作用域后,sp2析构,sp引用计数-1

3. pool库

boost.pool库,有4个组成部分:

  • 内存池 pool
  • 分配类实例的对象池 object_pool
  • 单件内存池 singleton_pool
  • 可用于标准库的 pool_alloc

3.1 内存池 pool

内存池:预先分配一块大的内存空间,然后就可以在其中使用某种算法实现高效快速的自定制内存分配。
pool库,返回一个简单数据类型(POD)的内存指针。

#include <boost/pool/pool.hpp>using namespace boost;#include <iostream>int* pool_test(pool<> &pl){    int *p = (int*)pl.malloc();  //分配    *p = 13;    std::cout << *p << std::endl;    return p;}int main(){    pool<> pl(sizeof(int));  //一个可分配Int的内存池    //std::cout << pl.get_max_size() << std::endl;    int *p = pool_test(pl);    std::cout << *p << std::endl;    pl.free(p);  //释放    //std::cout << *p << std::endl;    for (int i = 0; i < 100; i++){  //连续分配大量的内存        pl.ordered_malloc(10);    }}  //退出作用域后,内存池对象析构,所分配的内存在这里都被释放。

3.2 对象池 object_pool

对象池功能与内存池类似,但会在析构时对所有已经分配的内存块调用析构函数,从而正确的释放资源。

boost::object_pool类摘要

// In header: <boost/pool/object_pool.hpp>template<typename T> class object_pool : protected boost::pool {public:  // types  typedef T                                      element_type;     // ElementType.   //struct/copy/destruct  explicit object_pool();  ~object_pool();  // public member functions  element_type * malloc();  void free(element_type *const);  //malloc()和free()函数用于分配和释放一块类型为ElementType* 内存块,  //但并不调用类的构造函数和析构函数,也就是说操作的是一块原始内存块,里面的值是未定义的,  //尽量少使用  bool is_from(element_type *const) const;  element_type * construct();  void destroy(element_type *const);  //这两个函数是object_pool的真正价值所在。  //construct()先调用malloc()分配内存,然后在内存块上调用类的构造函数,返回一个已经初始化的对象指针。  //destroy()则先调用对象的析构函数,然后再free()释放内存};

使用:

#include <boost/pool/pool.hpp>using namespace boost;#include <iostream>class ClassName{public:    ClassName(int m, int n) :a(m), b(n){}    int a;    int b;};void object_pool_test(){    object_pool<ClassName> op;    ClassName* p = op.construct(13, 5);    std::cout << p->a <<" "<< p->b << std::endl;}  //退出时,所有创建的对象都被正确的析构,释放内存。

3.3 单件池 singleton_pool

#include <boost/pool/singleton_pool.hpp>using namespace boost;#include <iostream>//struct pool_tag{};  //仅仅用于标记的空类//typedef singleton_pool<pool_tag, sizeof(int)> spl;  //内存池定义//内存池定义:直接在模板参数列表中声明tag类,这样可以在一条语句中完成对singleton_pool的类型定义。typedef singleton_pool<struct pool_tag, sizeof(int)> spl;  void singleton_test(){    int *p = (int*)spl::malloc();  //分配一个整数内存块    //assert(spl::is_from(p));    spl::release_memory();  //释放所有未分配的内存    *p = 13;    std::cout << *p << std::endl;}  //sql的内存直到程序结束才释放,而不是退出作用域。
0 0