1.1 数组的特点
- 连续的内存空间分配并且顺序存储数据,使用之前需要先分配数组个数;
- 可以通过下标进行访问修改数据,时间复杂度为O(1);
- 空间效率不是很好,不能随意修改数组大小;
- 增删数据需要内存拷贝
1.2 链表的特点
- 内存空间分配是分散的,非连续的存储数据;
- 不能通过下标直接访问,查找的时间复杂度为O(n);
- 增删元素,只需要改变前后指针;
1.3 基于数组和指针实现的对象管理器
结合了数组和链表的优点,可以O(1)查找元素,O(1)增删元素;
需要预分配内存;
2.代码实现(C++)
/** *@file ObjAllocator *@author jasonxiong *@date 2009-12-09 *@version 1.0 *@brief CObj对象分配类,即新版本的idxobj * * (1)一般用于大型对象的内存分配 */ #ifndef __OBJ_ALLOCATOR_HPP__ #define __OBJ_ALLOCATOR_HPP__ #include <stdio.h> namespace ServerLib { typedef enum enmObjAllocType { EOAT_ALLOC_BY_SELF = 0, //!<对象内存由ObjAllocator自已动态分配 EOAT_ALLOC_BY_SHARED_MEMORY = 1, //!<对象内存由共享内存分配 } ENMOBJALLOCTYPE; class CObj; typedef enum enmIdxUseFlag { EIUF_FREE = 0, //!<该对象未被使用 EIUF_USED = 1, //!<该对象已被使用 } ENMIDXUSEFLAG; //!索引类,仅在CObjAllocator中使用,外层一般不用 class CIdx { public: CIdx(); ~CIdx(); public: //!初始化函数 int Initialize(); //!将对象设置为未使用 inline void SetFree() { m_iUseFlag = EIUF_FREE; } //!将对象设置为已使用 inline void SetUsed() { m_iUseFlag = EIUF_USED; } //!判断对象是否已被使用 inline int IsUsed() const { return m_iUseFlag == EIUF_USED; } //!获取所在链表下一个索引 inline int GetNextIdx() const { return m_iNextIdx; } //!设置所在链表下一个索引 inline void SetNextIdx(int iIdx) { m_iNextIdx = iIdx; } //!获取所在链表上一个索引 inline int GetPrevIdx() const { return m_iPrevIdx; } //!设置所在链表上一个索引 inline void SetPrevIdx(int iIdx) { m_iPrevIdx = iIdx; } //!获取指向的对象 inline CObj *GetAttachedObj() const { return m_pAttachedObj; } //!设置指向的对象 inline void SetAttachedObj(CObj *pObj) { m_pAttachedObj = pObj; } private: int m_iNextIdx; //!<对象索引块链表指针,指向后一个闲/忙索引 int m_iPrevIdx; //!<对象索引块链表指针,指向前一个闲/忙索引 int m_iUseFlag; //!<该对象是否已经被使用标志 CObj *m_pAttachedObj; //!<所指向的对象指针 }; typedef CObj *(*Function_CreateObj)(void *); class CObjAllocator { private: //默认构造函数,不允许上层自行调用 CObjAllocator(); public: CObjAllocator(size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj); ~CObjAllocator(); /** *使用共享内存创建ObjAllocator *@param[in] pszKeyFileName 共享内存Attach的文件名 *@param[in] ucKeyPrjID 共享内存的工程ID *@param[in] uiObjSize 对象大小 *@param[in] iObjCount 对象个数 *@param[in] *@return 0 success */ static CObjAllocator *CreateBySharedMemory(const char *pszKeyFileName, const unsigned char ucKeyPrjID, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj); /** *指定内存指针来创建CObjAllocator *@param[in] pszMemoryAddress 指定的内存 *@param[in] uiMemorySize 内存大小 *@param[in] uiObjSize 对象大小 *@param[in] iObjCount 对象个数 *@param[in] pfCreateObj 创建CObj对象的函数,默认可以用DECLARE_DYN中的CreateObject *@return 0 success */ static CObjAllocator *CreateByGivenMemory(char *pszMemoryAddress, size_t uiMemorySize, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj); static size_t CountSize(size_t uiObjSize, int iObjCount); static CObjAllocator *ResumeByGivenMemory(char *pszMemoryAddress, size_t uiMemorySize, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj); public: //!初始化函数,将数据清空 int Initialize(); //!创建一个对象,成功返回对象ID,失败返回小于0的值 int CreateObject(); //!创建一个对象, 并指定其ID,成功返回对象ID,失败返回小于0的值 int CreateObjectByID(int iID); //!根据对象ID销毁一个对象,成功返回0 int DestroyObject(int iObjectID); //!根据ObjectID返回对象,必须保证该对象已被使用 CObj *GetObj(int iObjectID); //!根据ObjectID返回索引 CIdx *GetIdx(int iObjectID); //!获取已用对象链表头索引 inline int GetUsedHead() const { return m_iUsedHeadIdx; } //!获取空闲对象链表头索引 inline int GetFreeHead() const { return m_iFreeHeadIdx; } //获取已用对象个数 inline int GetUsedCount() const { return m_iUsedCount; } //获取空闲对象个数 inline int GetFreeCount() const { return m_iObjCount - m_iUsedCount; } //!在接口返回错误时,调用这个函数获取错误号 inline int GetErrorNO() const { return m_iErrorNO; } //获取对象分配类型 inline int GetObjAllocType() const { return m_shObjAllocType; } //!获取下一个对象 CObj *GetNextObj(int iObjectID); //!设置对象初始化指针 inline void SetCreateObjFunc(Function_CreateObj pfCreateObjFunc) { m_pfCreateObjFunc = pfCreateObjFunc; } private: //!设置错误号 inline void SetErrorNO(int iErrorNO) { m_iErrorNO = iErrorNO; } private: //这几个对象只有在构造函数时确定,后面不会更改 short m_shObjAllocType; //!<对象分配类型 size_t m_uiObjSize; //!<单个对象 int m_iObjCount; //!<最多分配的对象个数 CIdx *m_astIdxs; //!<索引数组,用于管理对象链表 CObj *m_pstObjBuffer; //!<分配的对象内存 Function_CreateObj m_pfCreateObjFunc; //!<在内存上创建CObj对象的函数,每个子类需要自己实现 //以下的对象会更改,调用Initialize初始化 int m_iErrorNO; //!<错误码 int m_iFreeHeadIdx; //!<空闲对象链表头索引 int m_iFreeTailIdx; //!<空闲对象链表尾索引 int m_iUsedHeadIdx; //!<已用对象链表头索引 int m_iUsedCount; //!<已用对象个数 }; //!基本对象类 class CObj { public: CObj() {} virtual ~CObj() {} public: //!对象的初始化函数,在CObjAllocator创建对象时会调用,所以子类一定要实现 virtual int Initialize() = 0; //!显示对象函数,可重载 virtual int Show() const { return 0; } //!获取对象ID inline int GetObjectID() const { return m_iObjectID; } //!设置对象ID inline void SetObjectID(int iObjectID) { m_iObjectID = iObjectID; } virtual int Resume() { return 0; } private: int m_iObjectID; //!对象ID,即在CObjAllocator中的数组下标 friend int CObjAllocator::Initialize(); //!<在这个函数中需要直接赋值m_iObjectID,所以设为友元 }; #define DECLARE_DYN public: void *operator new(size_t uiSize, const void *pThis) throw(); static CObj *CreateObject(void *pMem); #define IMPLEMENT_DYN(class_name) void *class_name::operator new(size_t uiSize, const void *pThis) throw() { if (!pThis) { return NULL; } return (void *)pThis; } CObj *class_name::CreateObject(void *pMem) { return (CObj *)new (pMem) class_name; } } // namespace ServerLib #endif //__OBJ_ALLOCATOR_HPP__ ///:~ /** *@file ObjAllocator.cpp *@author jasonxiong *@date 2009-12-14 *@version 1.0 *@brief 对象分配类的实现文件 * * */ #include <assert.h> #include "ErrorDef.hpp" #include "ObjAllocator.hpp" #include "SharedMemory.hpp" using namespace ServerLib; CIdx::CIdx() { Initialize(); } CIdx::~CIdx() { } int CIdx::Initialize() { m_iNextIdx = -1; m_iPrevIdx = -1; m_iUseFlag = 0; m_pAttachedObj = NULL; return 0; } CObjAllocator::CObjAllocator() { } //void* CObjAllocator::operator new(unsigned int uiSize, const void* pThis) throw() //{ // if(!pThis) // { // return NULL; // } // // return (void*)pThis; //} CObjAllocator::CObjAllocator(size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj) { __ASSERT_AND_LOG(uiObjSize > 0 && iObjCount > 0 && pfCreateObj); m_shObjAllocType = EOAT_ALLOC_BY_SELF; m_iObjCount = iObjCount; m_uiObjSize = uiObjSize; m_pfCreateObjFunc = pfCreateObj; m_astIdxs = new CIdx[m_iObjCount]; size_t uiObjMemorySize = uiObjSize * iObjCount; char *pstObjMem = new char[uiObjMemorySize]; m_pstObjBuffer = (CObj *)pstObjMem; __ASSERT_AND_LOG(m_astIdxs && m_pstObjBuffer); Initialize(); } size_t CObjAllocator::CountSize(size_t uiObjSize, int iObjCount) { return sizeof(CObjAllocator) + uiObjSize * iObjCount + iObjCount * sizeof(CIdx); } CObjAllocator *CObjAllocator::CreateByGivenMemory(char *pszMemoryAddress, size_t uiMemorySize, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj) { if (pszMemoryAddress == NULL || uiObjSize <= 0 || iObjCount <= 0 || pfCreateObj == NULL) { TRACESVR("%p, %d, %d, %p.\n", pszMemoryAddress, (int)uiObjSize, iObjCount, pfCreateObj); return NULL; } size_t uiSharedMemorySize = sizeof(CObjAllocator) + uiObjSize * iObjCount + iObjCount * sizeof(CIdx); if (uiSharedMemorySize > uiMemorySize) { TRACESVR("ObjAllocator: alloc size %lu > sh size %lu.\n", (unsigned long)uiSharedMemorySize, (unsigned long)uiMemorySize); return NULL; } //在指定的内存地址上分配CObjAllocator CObjAllocator *pstObjAllocator = (CObjAllocator *)pszMemoryAddress; if (!pstObjAllocator) { TRACESVR("ObjAllocator: pstObjAllocator is NULL.\n"); return NULL; } pstObjAllocator->m_uiObjSize = uiObjSize; pstObjAllocator->m_iObjCount = iObjCount; pstObjAllocator->m_pfCreateObjFunc = pfCreateObj; pstObjAllocator->m_shObjAllocType = EOAT_ALLOC_BY_SHARED_MEMORY; pstObjAllocator->m_astIdxs = (CIdx *)((unsigned char *)pszMemoryAddress + sizeof(CObjAllocator)); pstObjAllocator->m_pstObjBuffer = (CObj *)((unsigned char *)pszMemoryAddress + sizeof(CObjAllocator) + iObjCount * sizeof(CIdx)); pstObjAllocator->Initialize(); return pstObjAllocator; } CObjAllocator *CObjAllocator::ResumeByGivenMemory(char *pszMemoryAddress, size_t uiMemorySize, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj) { if ((NULL == pszMemoryAddress) || (uiObjSize <= 0) || (iObjCount <= 0)) { return NULL; } size_t uiSharedMemorySize = sizeof(CObjAllocator) + uiObjSize * iObjCount + sizeof(CIdx) * iObjCount; if (uiSharedMemorySize > uiMemorySize) { return NULL; } CObjAllocator *pstObjAllocator = (CObjAllocator *)pszMemoryAddress; if ((pstObjAllocator->m_uiObjSize != uiObjSize) || (pstObjAllocator->m_iObjCount != iObjCount)) { return NULL; } pstObjAllocator->m_shObjAllocType = EOAT_ALLOC_BY_SHARED_MEMORY; pstObjAllocator->m_astIdxs = (CIdx *)((unsigned char *)pszMemoryAddress + sizeof(CObjAllocator)); pstObjAllocator->m_pstObjBuffer = (CObj *)((unsigned char *)pszMemoryAddress + sizeof(CObjAllocator) + iObjCount * sizeof(CIdx)); int i; // 重新绑定obj和idx for (i = 0; i < iObjCount; ++i) { // 调用placement-new, 恢复类的虚函数表. CObj *pstObj = (*pfCreateObj)((unsigned char *)pstObjAllocator->m_pstObjBuffer + uiObjSize * i); __ASSERT_AND_LOG(pstObj->GetObjectID() == i); pstObjAllocator->m_astIdxs[i].SetAttachedObj(pstObj); } pstObjAllocator->SetCreateObjFunc(pfCreateObj); return pstObjAllocator; } CObjAllocator *CObjAllocator::CreateBySharedMemory(const char *pszKeyFileName, const unsigned char ucKeyPrjID, size_t uiObjSize, int iObjCount, Function_CreateObj pfCreateObj) { if (pszKeyFileName == NULL || uiObjSize <= 0 || iObjCount <= 0 || pfCreateObj == NULL) { return NULL; } CSharedMemory stSharedMemory; size_t uiSharedMemorySize = sizeof(CObjAllocator) + uiObjSize * iObjCount + iObjCount * sizeof(CIdx); int iRet = stSharedMemory.CreateShmSegment(pszKeyFileName, ucKeyPrjID, (int)uiSharedMemorySize); if (iRet) { return NULL; } //在共享内存的地址上分配CObjAllocator CObjAllocator *pstObjAllocator = (CObjAllocator *)stSharedMemory.GetFreeMemoryAddress(); if (!pstObjAllocator) { return NULL; } pstObjAllocator->m_uiObjSize = uiObjSize; pstObjAllocator->m_iObjCount = iObjCount; pstObjAllocator->m_pfCreateObjFunc = pfCreateObj; pstObjAllocator->m_shObjAllocType = EOAT_ALLOC_BY_SHARED_MEMORY; pstObjAllocator->m_astIdxs = (CIdx *)((unsigned char *)stSharedMemory.GetFreeMemoryAddress() + sizeof(CObjAllocator)); pstObjAllocator->m_pstObjBuffer = (CObj *)((unsigned char *)stSharedMemory.GetFreeMemoryAddress() + sizeof(CObjAllocator) + iObjCount * sizeof(CIdx)); return pstObjAllocator; } CObjAllocator::~CObjAllocator() { if (m_shObjAllocType == EOAT_ALLOC_BY_SELF) { if (m_astIdxs) { delete[] m_astIdxs; m_astIdxs = NULL; } if (m_pstObjBuffer) { char *pstObjMem = (char *)m_pstObjBuffer; delete[] pstObjMem; m_pstObjBuffer = NULL; } } } int CObjAllocator::Initialize() { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return -1; } if (m_iObjCount <= 0) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_COUNT); return -2; } //初始化索引数组 int i; for (i = 0; i < m_iObjCount; ++i) { m_astIdxs[i].Initialize(); m_astIdxs[i].SetPrevIdx(i - 1); m_astIdxs[i].SetNextIdx(i + 1); } m_astIdxs[m_iObjCount - 1].SetNextIdx(-1); //初始化对象数组 for (i = 0; i < m_iObjCount; ++i) { CObj *pstObj = (*m_pfCreateObjFunc)((unsigned char *)m_pstObjBuffer + m_uiObjSize * i); pstObj->m_iObjectID = i; m_astIdxs[i].SetAttachedObj(pstObj); } m_iErrorNO = 0; m_iFreeHeadIdx = 0; m_iFreeTailIdx = m_iObjCount - 1; m_iUsedHeadIdx = -1; m_iUsedCount = 0; return 0; } int CObjAllocator::CreateObject() { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return -1; } if (m_iUsedCount >= m_iObjCount) { SetErrorNO(EEN_OBJ_ALLOCATOR__OBJ_IS_FULL); return -2; } if (m_iFreeHeadIdx < 0 || m_iFreeHeadIdx >= m_iObjCount) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return -3; } //修改空闲链表 int iCurIdx = m_iFreeHeadIdx; m_iFreeHeadIdx = m_astIdxs[m_iFreeHeadIdx].GetNextIdx(); if (m_iFreeHeadIdx >= 0) { m_astIdxs[m_iFreeHeadIdx].SetPrevIdx(-1); } if (iCurIdx == m_iFreeTailIdx) { m_iFreeTailIdx = -1; } //挂到使用链表 m_astIdxs[iCurIdx].SetUsed(); m_astIdxs[iCurIdx].SetNextIdx(m_iUsedHeadIdx); m_astIdxs[iCurIdx].SetPrevIdx(-1); if (m_iUsedHeadIdx >= 0) { m_astIdxs[m_iUsedHeadIdx].SetPrevIdx(iCurIdx); } //初始化对象 m_iUsedHeadIdx = iCurIdx; CObj *pstObj = m_astIdxs[iCurIdx].GetAttachedObj(); if (NULL == pstObj) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return -4; } #ifdef OBJ_MEMSET_ON_CREATE memset(pstObj, 0, m_uiObjSize); (*m_pfCreateObjFunc)((unsigned char *)pstObj); pstObj->SetObjectID(iCurIdx); #endif pstObj->Initialize(); ++m_iUsedCount; __ASSERT_AND_LOG(pstObj->GetObjectID() == iCurIdx); return iCurIdx; } int CObjAllocator::CreateObjectByID(int iID) { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return -1; } if (iID < 0 || iID >= m_iObjCount) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return -2; } if (m_astIdxs[iID].IsUsed()) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return -3; } //修改空闲链表 int iCurIdx = iID; int iPrevIdx = m_astIdxs[iCurIdx].GetPrevIdx(); int iNextIdx = m_astIdxs[iCurIdx].GetNextIdx(); if (iPrevIdx >= 0) { m_astIdxs[iPrevIdx].SetNextIdx(iNextIdx); } if (iNextIdx >= 0) { m_astIdxs[iNextIdx].SetPrevIdx(iPrevIdx); } if (iCurIdx == m_iFreeHeadIdx) { m_iFreeHeadIdx = iNextIdx; } if (iCurIdx == m_iFreeTailIdx) { m_iFreeTailIdx = -1; } //挂到使用链表 m_astIdxs[iCurIdx].SetUsed(); m_astIdxs[iCurIdx].SetNextIdx(m_iUsedHeadIdx); m_astIdxs[iCurIdx].SetPrevIdx(-1); if (m_iUsedHeadIdx >= 0) { m_astIdxs[m_iUsedHeadIdx].SetPrevIdx(iCurIdx); } m_iUsedHeadIdx = iCurIdx; // add by cary CObj *pstObj = m_astIdxs[iCurIdx].GetAttachedObj(); #ifdef OBJ_MEMSET_ON_CREATE memset(pstObj, 0, m_uiObjSize); (*m_pfCreateObjFunc)((unsigned char *)pstObj); pstObj->SetObjectID(iCurIdx); #endif pstObj->Initialize(); ++m_iUsedCount; __ASSERT_AND_LOG(pstObj->GetObjectID() == iCurIdx); return iCurIdx; } int CObjAllocator::DestroyObject(int iObjectID) { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return -1; } if (iObjectID >= m_iObjCount || iObjectID < 0 || m_iObjCount <= 0) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return -2; } if (!m_astIdxs[iObjectID].IsUsed()) { SetErrorNO(EEN_OBJ_ALLOCATOR__DESTROY_FREE_OBJ); return -3; } //从已用链表中删除 int iCurIdx = iObjectID; int iPrevIdx = m_astIdxs[iCurIdx].GetPrevIdx(); int iNextIdx = m_astIdxs[iCurIdx].GetNextIdx(); if (iPrevIdx >= 0) { m_astIdxs[iPrevIdx].SetNextIdx(iNextIdx); } if (iNextIdx >= 0) { m_astIdxs[iNextIdx].SetPrevIdx(iPrevIdx); } if (iCurIdx == m_iUsedHeadIdx) { m_iUsedHeadIdx = iNextIdx; } //挂入空闲链表尾部 m_astIdxs[iObjectID].SetFree(); m_astIdxs[iObjectID].SetPrevIdx(m_iFreeTailIdx); m_astIdxs[iObjectID].SetNextIdx(-1); if (m_iFreeHeadIdx == -1) { m_iFreeHeadIdx = iCurIdx; } if (m_iFreeTailIdx >= 0) { m_astIdxs[m_iFreeTailIdx].SetNextIdx(iCurIdx); } m_iFreeTailIdx = iCurIdx; --m_iUsedCount; return 0; } CObj *CObjAllocator::GetObj(int iObjectID) { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return NULL; } if (iObjectID < 0 || iObjectID >= m_iObjCount) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return NULL; } if (!m_astIdxs[iObjectID].IsUsed()) { SetErrorNO(EEN_OBJ_ALLOCATOR__GET_FREE_OBJ); return NULL; } return m_astIdxs[iObjectID].GetAttachedObj(); } CIdx *CObjAllocator::GetIdx(int iObjectID) { if (m_pstObjBuffer == NULL || m_astIdxs == NULL) { SetErrorNO(EEN_OBJ_ALLOCATOR__NULL_POINTER); return NULL; } if (iObjectID < 0 || iObjectID >= m_iObjCount) { SetErrorNO(EEN_OBJ_ALLOCATOR__INVALID_OBJ_INDEX); return NULL; } if (!m_astIdxs[iObjectID].IsUsed()) { SetErrorNO(EEN_OBJ_ALLOCATOR__GET_FREE_OBJ); return NULL; } return &m_astIdxs[iObjectID]; } CObj *CObjAllocator::GetNextObj(int iObjectID) { CIdx *pIdx = GetIdx(iObjectID); if (!pIdx) { return NULL; } int iNextObjIdx = pIdx->GetNextIdx(); return GetObj(iNextObjIdx); }
源码地址:https://github.com/dai543103/ServerFramework-1/blob/master/001_ServerLib/BaseLibs/ObjAllocator.hpp
原文地址:https://www.cnblogs.com/yzdai/p/11442172.html
时间: 2024-10-25 02:52:35