为了实现面向对象编程,对于的复杂型结构快速构造与释放,写了个内存池管理模板。他特点是允许用户放弃内存池生成对象使用权,而不是执行析构。实现对象的复用。
- 实现同类型对象的全局化管理。无需显示构造内存池。采用newOne宏申请对象。
- 内存块的大小可调。内存池状态可输出显示。
- 采用内存预分配方式。对象构造采用原始构造,非动态申请和复制构造,提高速度。
- 加锁,实现多线程支持。(加锁会额外耗费cpu时间,可设置宏
CLMP_USE_LOCK_TYPE
,决定采用哪种方案)
#define CLMP_USE_LOCK_TYPE 0
- 通过giveUpOne()方法,放弃对象使用权,不需要释放对象,实现快速对象复用。
演示代码:应用案例: 【C++高速矩阵类实现】.
struct MyStruct
{
int * c;
string name;
MyStruct(const char* lpName = "" )
:c(new int[100]) , name(lpName)
{
cout << "\nMyStruct 构造!: " << name << endl;
}
~MyStruct() {
delete[] c;
cout << "\nMyStruct 析构! " << name << endl;
}
};
int main() {
auto p1 = newOne(MyStruct,"p1");
giveUpOne(p1);
auto p2 = newOne(MyStruct,"p2");
if (p1 == p2)
cout << "\np2 获得了复用对象: " << p2->name << endl;
auto p3 = newOne(MyStruct, "p3");
deleteOne(p1);
deleteOne(p2);
deleteOne(p3);
getchar();
return 1;
运行结果:

模板库头源码:
CLMemPool.h
#pragma once
#ifndef __CL_MEMPOOL_H__
#define __CL_MEMPOOL_H__
#include <cassert>
#include <map>
#include <string>
#include <stdexcept>
#define CLMP_USE_LOCK_TYPE 0
#if CLMP_USE_LOCK_TYPE == 2
#include "windows.h"
class CLLock {
private:
CRITICAL_SECTION cs;
public:
CLLock() { InitializeCriticalSection(&cs); }
~CLLock() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
};
#elif CLMP_USE_LOCK_TYPE == 1
#include <mutex>
class CLLock {
private:
std::mutex mt;
public:
void lock() { mt.lock(); }
void unlock() { mt.unlock(); }
};
#else
class CLLock {
public:
void lock() {}
void unlock() {}
};
#endif
#ifndef _CL_DIFVARS_SUPPORT_
#define _CL_DIFVARS_SUPPORT_
#ifdef UNICODE
typedef wchar_t Char;
#define tstring wstring
#ifndef _T
#define _T(x) L ## x
#endif
#ifndef _tprintf_s
#define _tprintf_s wprintf_s
#define _stprintf_s swprintf_s
#define _tcscpy_s wcscpy_s
#endif
#else
typedef char Char;
#define tstring string
#ifndef _T
#define _T(x) x
#endif
#ifndef _tprintf_s
#define _tprintf_s printf_s
#define _stprintf_s sprintf_s
#define _tcscpy_s strcpy_s
#endif
#endif
typedef const Char* PCStr;
typedef Char* PStr;
#ifndef BUFSIZE
#define BUFSIZE 256
#endif
#ifndef max
#define max(a,b) ((a) < (b) ? (b) : (a))
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#endif
template <typename classTag>
class CLMemPoolBlock;
template <typename classTag>
class CLMemPool;
class MemPoolsTable
:public std::map< CLMemPool<void*>*, std::tstring>,
public CLLock
{};
inline MemPoolsTable* getMemPoolsTable() {
static MemPoolsTable _mplst;
return &_mplst;
}
inline void addMemPoolToTable(PCStr name, CLMemPool<void*>* pMemPool)
{
getMemPoolsTable()->lock();
(*getMemPoolsTable())[pMemPool] = (name == nullptr ? _T("") : name);
getMemPoolsTable()->unlock();
}
template <typename classTag>
class CLMemPoolUnit {
friend class CLMemPool<classTag>;
friend class CLMemPoolBlock<classTag>;
public:
struct DataHead {
CLMemPoolUnit<classTag>* pPre;
CLMemPoolUnit<classTag>* pNext;
CLMemPoolBlock<classTag>* pThisBlock;
bool bIsCreate;
bool bIsUsed;
};
private:
DataHead hdr;
classTag data;
CLMemPoolUnit<classTag>* init(
CLMemPoolBlock<classTag>* _pThisBlock = 0,
CLMemPoolUnit<classTag>* _pPre = 0,
CLMemPoolUnit<classTag>* _pNext = 0,
bool _isCreate = false,
bool _isUsed = false
) {
hdr.pThisBlock = _pThisBlock;
hdr.pPre = _pPre;
hdr.pNext = _pNext;
hdr.bIsCreate = _isCreate;
hdr.bIsUsed = _isUsed;
return this;
}
CLMemPoolUnit(){}
template <typename... Args>
CLMemPoolUnit(Args&&... args):data(std::forward<Args>(args)...){}
~CLMemPoolUnit() {}
public:
inline CLMemPoolBlock<classTag>* getOwnerBlock() {return hdr.pThisBlock;}
};
#define MUHEARDER( classTag, pData ) ((CLMemPoolUnit<classTag>*)(((char*)(pData))-(sizeof(CLMemPoolUnit<classTag>::DataHead))))
template <typename classTag>
class CLMemPoolBlock {
friend class CLMemPool<classTag>;
friend class CLMemPoolUnit<classTag>;
private:
explicit CLMemPoolBlock(size_t PerBlockMemCapacity_MB , CLMemPool<classTag>* _pOwnerMemPool)
:pOwnerMemPool(_pOwnerMemPool)
{
init();
alloc(PerBlockMemCapacity_MB * 1024 * 1024 / sizeof(CLMemPoolUnit<classTag>));
}
virtual ~CLMemPoolBlock() {
releaseObjMenBlock();
}
inline bool isUsable() {
return pUsableLst ? true : false;
}
CLMemPoolUnit<classTag>* freeOneData(CLMemPoolUnit<classTag>* pUnit) {
assert(pUnit !=nullptr);
if (pUnit->hdr.bIsCreate) {
pUnit->CLMemPoolUnit<classTag>::~CLMemPoolUnit();
pUnit->hdr.bIsCreate = false;
nHasCreatedCounts--;
}
return putToUsable(pUnit);
}
CLMemPoolUnit<classTag>* giveUpOneData(CLMemPoolUnit<classTag>* pUnit) {
assert(pUnit != nullptr);
return putToUsable(pUnit);
}
template <typename... Args>
classTag* getOneData(Args&&... args) {
assert(pUsableLst != nullptr);
if(!pUsableLst->hdr.bIsCreate) {
pUsableLst->CLMemPoolUnit<classTag>::CLMemPoolUnit(std::forward<Args>(args)...);
pUsableLst->hdr.bIsCreate = true;
nHasCreatedCounts++;
}
return putToUnusable(pUsableLst);
}
inline void init() {
pUsableLst = 0;
nMaxUsable = 0;
pUnusableLst = 0;
nMaxUnusable = 0;
nHasCreatedCounts = 0;
pPre = 0;
pNext = 0;
pMainDataLst = 0;
nMaxDataCounts = 0;
}
void alloc(size_t unitCounts = 1) {
assert(pMainDataLst == 0 && pUsableLst == 0 && pUnusableLst == 0);
if (pMainDataLst == 0) {
pMainDataLst = (CLMemPoolUnit<classTag> *)malloc(sizeof(CLMemPoolUnit<classTag>)*(nMaxDataCounts = nMaxUsable = (unitCounts == 0 ? 1 : unitCounts)));
pUsableLst = &pMainDataLst[0];
pMainDataLst[0].init(this, 0, nMaxDataCounts <= 1 ? 0 : &pMainDataLst[1]);
for (size_t i = 1; i < nMaxDataCounts-1; ++i) {
pMainDataLst[i].init(this, &pMainDataLst[i-1], &pMainDataLst[i + 1]);
}
pMainDataLst[nMaxDataCounts - 1].init(this, nMaxDataCounts <= 1 ? 0 : &pMainDataLst[nMaxDataCounts - 2], 0);
}
};
void distructCreatedUsable() {
if (nHasCreatedCounts == 0)
return;
for (CLMemPoolUnit<classTag>* pc = pUsableLst; pc != nullptr; ) {
if (pc->hdr.bIsCreate) {
pc->CLMemPoolUnit<classTag>::~CLMemPoolUnit();
pc->hdr.bIsCreate = false;
nHasCreatedCounts--;
}
pc = pc->hdr.pNext;
}
}
void releaseObjMenBlock() {
if (pMainDataLst) {
for (CLMemPoolUnit<classTag>* pc = pUnusableLst; pc != nullptr; ) {
pUnusableLst = freeOneData(pc);
pc->init();
pc = pUnusableLst;
}
free(pMainDataLst);
pMainDataLst = 0;
}
}
#define _extruct_pUnitBlock(pUnit) \
((((pUnit)->pPre) ? ((pUnit)->pPre->pNext = (pUnit)->pNext) : 0),(((pUnit)->pNext)?((pUnit)->pNext->pPre = (pUnit)->pPre):0),(pUnit))
#define _extruct_pUnit(pUnit) \
((((pUnit)->hdr.pPre) ? ((pUnit)->hdr.pPre->hdr.pNext = (pUnit)->hdr.pNext) : 0),(((pUnit)->hdr.pNext)?((pUnit)->hdr.pNext->hdr.pPre = (pUnit)->hdr.pPre):0),(pUnit))
CLMemPoolUnit<classTag>* putToUsable(CLMemPoolUnit<classTag>* pUnit) {
assert(this == pUnit->hdr.pThisBlock);
pUnit->hdr.bIsUsed = false;
if (pUnusableLst && pUnusableLst == pUnit)
pUnusableLst = pUnit->hdr.pNext;
_extruct_pUnit(pUnit);
if (pUsableLst) {pUsableLst->hdr.pPre = pUnit;}
pUnit->hdr.pNext = pUsableLst;
pUnit->hdr.pPre = 0;
pUsableLst = pUnit;
nMaxUnusable -= 1;
nMaxUsable += 1;
return pUnusableLst;
}
classTag* putToUnusable(CLMemPoolUnit<classTag>* pUnit) {
assert(this == pUnit->hdr.pThisBlock);
pUnit->hdr.bIsUsed = true;
if (pUsableLst && pUsableLst == pUnit)
pUsableLst = pUnit->hdr.pNext;
_extruct_pUnit(pUnit);
if (pUnusableLst) { pUnusableLst->hdr.pPre = pUnit;}
pUnit->hdr.pNext = pUnusableLst;
pUnit->hdr.pPre = 0;
pUnusableLst = pUnit;
nMaxUnusable += 1;
nMaxUsable -= 1;
return &pUnit->data;
}
CLMemPool<classTag>* const pOwnerMemPool;
CLMemPoolUnit<classTag>* pMainDataLst;
size_t nMaxDataCounts;
CLMemPoolUnit<classTag>* pUsableLst;
size_t nMaxUsable;
CLMemPoolUnit<classTag>* pUnusableLst;
size_t nMaxUnusable;
size_t nHasCreatedCounts;
CLMemPoolBlock<classTag>* pPre;
CLMemPoolBlock<classTag>* pNext;
public:
inline CLMemPool<classTag>* getOwnerMemPool() { return pOwnerMemPool;}
};
class IMenPool{
public:
virtual void arrangement(bool) = 0;
virtual void deallocateOne(void*) = 0;
virtual void giveUpOne(void*) = 0;
};
template <typename classTag>
class CLMemPool :public IMenPool,public CLLock {
friend class CLMemPoolBlock<classTag>;
friend class CLMemPoolUnit<classTag>;
private:
CLMemPool(PCStr _lpTypeName, size_t PerBlockMemCapacity_MB = 5) :
pEntry(nullptr),
pCurrentUsingBlock(nullptr)
{
setPerBlockMemCapacity(PerBlockMemCapacity_MB);
setMemPoolTypeName(_lpTypeName);
}
CLMemPool(size_t PerBlockMemCapacity_MB = 5) :
pEntry(nullptr),
pCurrentUsingBlock(nullptr)
{
setPerBlockMemCapacity(PerBlockMemCapacity_MB);
setMemPoolTypeName(nullptr);
}
public:
PCStr lpTypeName;
virtual ~CLMemPool() {
arrangement();
getMemPoolsTable()->lock();
for (auto i = ::getMemPoolsTable()->find((CLMemPool<void*>*)this);
i != ::getMemPoolsTable()->end(); ){
::getMemPoolsTable()->erase(i);
break;
}
getMemPoolsTable()->unlock();
}
void setMemPoolTypeName(PCStr _lpTypeName) {
lpTypeName = _lpTypeName ;
::addMemPoolToTable(lpTypeName, (CLMemPool<void*>*)this);
}
virtual void arrangement(bool distructCreatedButNoUsed = true) {
lock();
pCurrentUsingBlock = nullptr;
for (CLMemPoolBlock<classTag>* pi = pEntry; pi != nullptr; )
{
CLMemPoolBlock<classTag>* pib = pi->pNext;
if (distructCreatedButNoUsed)
pi->distructCreatedUsable();
if (pi->nMaxUnusable == 0 && pi->nHasCreatedCounts == 0) {
if (pEntry == pi)
pEntry = pi->pNext;
delete _extruct_pUnitBlock(pi);
}
pi = pib;
}
unlock();
}
virtual void releaseObjMenPool() {
lock();
for (CLMemPoolBlock<classTag>* pi = pEntry; pi != nullptr; )
{
pCurrentUsingBlock = pi->pNext;
delete pi;
pi = pCurrentUsingBlock;
}
m_PerBlockMemCapacity = 0;
pEntry = 0;
pCurrentUsingBlock = 0;
unlock();
}
template <typename... Args>
classTag* allocateOne(Args&&... args) {
lock();
classTag* rt = getAvailableBlock()->getOneData(std::forward<Args>(args)...);
unlock();
return rt;
}
virtual void deallocateOne(void* pDelete) {
CLMemPoolUnit<classTag>* pUnit = MUHEARDER(classTag,pDelete);
if(!checkPtrValidity(pUnit))return;
lock();
pUnit->hdr.pThisBlock->freeOneData(pUnit);
unlock();
}
virtual void giveUpOne(void* pDelete) {
CLMemPoolUnit<classTag>* pUnit = MUHEARDER(classTag, pDelete);
if (!checkPtrValidity(pUnit))return;
lock();
pUnit->hdr.pThisBlock->giveUpOneData(pUnit);
unlock();
}
bool checkPtrValidity(CLMemPoolUnit<classTag>* pUnit){
if(pUnit->hdr.pThisBlock->pOwnerMemPool != this)
throw std::runtime_error("Tag obj is not created by this mem pool!");
if (!pUnit->hdr.bIsUsed) {
#ifdef _DEBUG
if(pUnit->hdr.bIsCreate)
throw std::runtime_error("Tag obj has been give up!");
else
throw std::runtime_error("Tag obj has been distructed!");
#else
return false;
#endif
}
return true;
}
virtual void setPerBlockMemCapacity(size_t PerBlockMemCapacity_MB = 5) {
lock();
m_PerBlockMemCapacity = PerBlockMemCapacity_MB == 0 ? 1 : PerBlockMemCapacity_MB;
unlock();
}
virtual size_t dumpInfo(bool bLog = true, bool bDeTail = false,PStr* outInfoString = nullptr) {
std::tstring strAll;
#define dumpInfoMax 1000
Char tem[dumpInfoMax];
if (bLog || outInfoString) {
if (bDeTail)
_stprintf_s(tem, dumpInfoMax,_T("\r\n>>The MemmeryPool(=%s) Dumper Detail----------------------------------- \r\n>>MemBlock Info:\r\n"),(lpTypeName ? lpTypeName:_T("#UnkownTypeName")));
else
_stprintf_s(tem, dumpInfoMax,_T("\r\n>>The MemmeryPool(=%s) Dumper Simple----------------------------------- \r\n"), (lpTypeName ? lpTypeName : _T("#UnkownTypeName")));
strAll += tem;
}
size_t si = 0;
size_t siu = 0;
size_t sit = 0;
lock();
for (const CLMemPoolBlock<classTag>* pc = pEntry; pc; )
{
si++;
siu += pc->nMaxUnusable;
sit += pc->nMaxDataCounts;
size_t n = pc->nMaxDataCounts == 0 ? 0 : (pc->nMaxUnusable * 50) / pc->nMaxDataCounts;
if ((bLog || outInfoString) && bDeTail) {
_stprintf_s(tem, dumpInfoMax,_T(">>MemBlock(%zd): ["), si); strAll += tem;
for (size_t i = 0; i < 50; ++i)
{
if (i < n)_stprintf_s(tem, dumpInfoMax,_T("*"));
else _stprintf_s(tem, dumpInfoMax,_T("-"));
strAll += tem;
}
_stprintf_s(tem, dumpInfoMax,_T("] <used=%zd%%>\r\n"), n * 2);
strAll += tem;
}
pc = pc->pNext;
}
unlock();
size_t perObj = sizeof(CLMemPoolUnit<classTag>);
size_t mem = perObj*sit + si*sizeof(CLMemPoolBlock<classTag>);
if (bLog || outInfoString) {
size_t Tb = 0, Gb = 0, Mb = 0, Kb = 0, Byte = 0;
Kb = mem / 1024; Byte = mem % 1024;
Mb = Kb / 1024; Kb = Kb % 1024;
Gb = Mb / 1024; Mb = Mb % 1024;
Tb = Gb / 1024; Gb = Gb % 1024;
if (Tb > 0)
_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdT %zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Tb, Gb, Mb, Kb, Byte, si, sit, siu);
else if (Gb > 0)
_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Gb, Mb, Kb, Byte, si, sit, siu);
else if (Mb > 0)
_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Mb, Kb, Byte, si, sit, siu);
else if (Kb > 0)
_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdK %zdB, blocks=%zd ,total=%zd, used=%zd.\r\n\r\n"), Kb, Byte, si, sit, siu);
else
_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Byte, si, sit, siu);
strAll += tem;
}
if (bLog)
_tprintf_s(_T("%s"),strAll.c_str());
if (outInfoString) {
size_t nn = strAll.length() + 1;
*outInfoString = new Char[nn];
_tcscpy_s(*outInfoString, nn, strAll.c_str());
}
return mem;
}
size_t getMemSize() const { return dumpInfo(false, false, nullptr); }
private:
CLMemPoolBlock<classTag>* pEntry;
CLMemPoolBlock<classTag>* pCurrentUsingBlock;
size_t m_PerBlockMemCapacity;
CLMemPoolBlock<classTag>* getAvailableBlock() {
if (pCurrentUsingBlock == nullptr) {
if (pEntry == nullptr) {
pCurrentUsingBlock = pEntry = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
}
else pCurrentUsingBlock = pEntry;
}
CLMemPoolBlock<classTag>* pStartBlock = pCurrentUsingBlock;
for (; pCurrentUsingBlock->isUsable() == false;)
{
if (pCurrentUsingBlock->pNext == nullptr) {
if (pCurrentUsingBlock != pEntry) {
pCurrentUsingBlock = pEntry;
}
else {
pStartBlock = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
if (pEntry->pNext)
pEntry->pNext->pPre = pStartBlock;
pStartBlock->pNext = pEntry->pNext;
pEntry->pNext = pStartBlock;
pCurrentUsingBlock = pStartBlock;
}
}
else if (pCurrentUsingBlock->pNext == pStartBlock) {
pStartBlock = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
if (pCurrentUsingBlock->pNext)
pCurrentUsingBlock->pNext->pPre = pStartBlock;
pStartBlock->pNext = pCurrentUsingBlock->pNext;
pCurrentUsingBlock->pNext = pStartBlock;
pCurrentUsingBlock = pStartBlock;
}
else pCurrentUsingBlock = pCurrentUsingBlock->pNext;
}
return pCurrentUsingBlock;
}
public:
static CLMemPool* getMenPool() {
static CLMemPool _MenPool;
return &_MenPool;
}
static CLMemPool* getMenPool(PCStr typeName) {
CLMemPool* pc = getMenPool();
if (pc->lpTypeName == nullptr && typeName != nullptr) {
pc->setMemPoolTypeName(typeName);
}
return pc;
}
template <typename... Args>
static classTag* newOneFromCLMemPool(PCStr name = nullptr, Args&&... args) {
return (classTag*)getMenPool(name)->allocateOne(std::forward<Args>(args)...);
}
static void setMemPoolBlockCapacity(size_t mb = 5) {
assert(mb != 0);
getMenPool()->setPerBlockMemCapacity(mb);
}
};
inline void deleteOneBackToCLMemPool(void* pDelete) {
assert(pDelete != nullptr);
MUHEARDER(void*, pDelete)->getOwnerBlock()->getOwnerMemPool()->deallocateOne(pDelete);
}
inline void giveUpOneBackToCLMemPool(void* pDelete) {
assert(pDelete != nullptr);
MUHEARDER(void*, pDelete)->getOwnerBlock()->getOwnerMemPool()->giveUpOne(pDelete);
}
#define newOne( typeName , ... ) (CLMemPool<typeName>::newOneFromCLMemPool(_T(#typeName) , __VA_ARGS__ ))
#define newOneAndNamed( typeName, NameString , ... ) (CLMemPool<typeName>::newOneFromCLMemPool(_T(#NameString), __VA_ARGS__ ))
#define deleteOne( pObjToDelete ) (deleteOneBackToCLMemPool((pObjToDelete)))
#define giveUpOne( pObjToDelete ) (giveUpOneBackToCLMemPool((pObjToDelete)))
inline void arrangeAllMemPools()
{
getMemPoolsTable()->lock();
for (auto& i : *getMemPoolsTable())
i.first->arrangement();
getMemPoolsTable()->unlock();
}
inline size_t dumpMemPoolsTable(bool bLog = true, bool bDeTail = false, PStr* outInfoString = nullptr)
{
size_t mem = 0;
PStr lpT = 0;
std::tstring str, strh;
if (bLog || outInfoString) {
if (bDeTail)strh = _T("\r\n>>>>The MemmeryPool Table Dumper Detail----------------------------------- \r\n");
else strh = _T("\r\n>>>>The MemmeryPool Table Dumper Simple----------------------------------- \r\n");
}
size_t ic = 1;
Char cts[BUFSIZE];
getMemPoolsTable()->lock();
for (auto i = getMemPoolsTable()->cbegin(); i != getMemPoolsTable()->cend(); ic++)
{
size_t memc = (i->first->dumpInfo(false, bDeTail, ((bLog || outInfoString) ? &lpT : nullptr)));
mem += memc;
if (bLog || outInfoString) {
if (i->first->lpTypeName)_stprintf_s(cts, _T("<MemPool(%zd)>, mem= %zd Bytes, type= %s \r\n"), ic, memc, i->second.c_str());
else _stprintf_s(cts, _T("<MemPool(%zd)>, mem= %zd Bytes, %s \r\n"), ic, memc, _T("#UnkownTypeName"));
strh += cts;
}
if (bLog || outInfoString) {
if (lpT) {
str += lpT;
delete[] lpT;
lpT = 0;
}
}
++i;
}
if (bLog || outInfoString) {
_stprintf_s(cts, _T(">>>>Total Mem = %zd Bytes \r\n\r\n>>>>Per MemmeryPool Information: \r\n"), mem);
strh += cts;
strh += str;
}
if (bLog)
_tprintf_s(_T("%s"), strh.c_str());
getMemPoolsTable()->unlock();
if (outInfoString) {
*outInfoString = new Char[strh.length() + 1];
_tcscpy_s(*outInfoString, strh.length() + 1, strh.c_str());
}
return mem;
}
#endif