简单的内存分配器

采用自定义的operator运算符实现自己的内存分配策略,在某些时候可以提高程序的效率。

 

C++中的new运算符,具体工作流程如下:

1.调用operator new申请原始内存

2.调用place new表达式,执行类的构造函数

3.返回内存地址

而delete操作符的工作是:

1.调用对象的析构函数

2.调用operator delete释放内存

例如:

#include <iostream>
using namespace std;

class Test
{
public:
    Test() { cout << "Test" << endl; }
    ~Test() { cout << "~Test" << endl; }
};

int main(int argc, char const *argv[])
{

    //这里的pt指向的是原始内存
    Test *pt = static_cast<Test*>(operator new[] (5 * sizeof(Test)));
    
    for(int ix = 0; ix != 5; ++ix)
    {
        new (pt+ix)Test(); //调用定位new运算式 执行构造函数
    }

    for(int ix = 0; ix != 5; ++ix)
    {
        pt[ix].~Test(); //调用析构函数,但是并未释放内存
    }
    operator delete[] (pt); //释放内存

}

 

这里提供一个简单的内存分配器基类,凡是继承该类的class均具有自定义的operator new 和 operator delete

此示例来自《C++Primer》第四版

大概思想是用static变量维持一个链表,管理空闲的内存块。

#ifndef CACHED_OBJECT_HPP
#define CACHED_OBJECT_HPP

#include <memory>
#include <stdexcept>
#include <iostream> //debug

template <typename T>
class CachedObject
{
public:
    void *operator new(std::size_t);
    void operator delete(void *, std::size_t);
    virtual ~CachedObject() { }
protected:
    T *next_;
private:
    static void addToFreeList(T*);  //将内存块加入链表
    static std::allocator<T> alloc_;//内存分配器
    static T *freeStore_;           //空闲内存的链表
    static const std::size_t chunk_;//一次分配的块数
};

template <typename T> std::allocator<T> CachedObject<T>::alloc_;
template <typename T> T *CachedObject<T>::freeStore_ = NULL;
template <typename T> const std::size_t CachedObject<T>::chunk_ = 24;

template <typename T>
void *CachedObject<T>::operator new(std::size_t sz)
{
    if(sz != sizeof(T))
        throw std::runtime_error("CachedObject: wrong size object in operator new");
    
    std::cout << "operator new " << std::endl; //DEBUG

    //没有空闲内存
    if(freeStore_ == NULL)
    {
        T *array = alloc_.allocate(chunk_);
        for(std::size_t ix = 0; ix != chunk_; ++ix)
        {
            addToFreeList(&array[ix]);
        }
    }

    //取出一块内存,从链表取出第一个元素
    T *p = freeStore_;
    freeStore_ = freeStore_->CachedObject<T>::next_;
    return p;
}

template <typename T>
void CachedObject<T>::operator delete(void *p, std::size_t)
{
    std::cout << "operator delete " << std::endl; //DEBUG

    if(p != NULL)
        addToFreeList(static_cast<T*>(p));
}


template <typename T>
void CachedObject<T>::addToFreeList(T *p)
{
    //使用头插法
    p->CachedObject<T>::next_ = freeStore_;
    freeStore_ = p;
}

#endif /* CACHED_OBJECT_HPP */

每次执行new时,调用我们自定义的operator new去空闲链表中取出一块内存,如果链表为空,则执行真正的申请内存操作。

每次delete时,把内存归还给链表。

这样减少了每次new都去申请内存的开销。

测试代码如下:

#include "CachedObject.hpp"
#include <iostream>
using namespace std;

//使用继承的策略去使用这个内存分配器
class Test : public CachedObject<Test>
{

};

int main(int argc, char const *argv[])
{
    
    //调用自定义的new分配内存
    Test *pt = new Test;
    delete pt;

    //调用默认的new和delete
    pt = ::new Test;
    ::delete pt;

    //不会调用自定义的new和delete
    pt = new Test[10];
    delete[] pt; 

}
posted on 2014-10-01 23:43  inevermore  阅读(961)  评论(0编辑  收藏  举报