现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

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

2019-12-19 17:23 工业·编程 ⁄ 共 3486字 ⁄ 字号 暂无评论

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_ptr

shared_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的内存直到程序结束才释放,而不是退出作用域。

给我留言

留言无头像?