对象池与operator重载
new作为关键字和运算符 operator new can be called explicitly as a regular function, but in C++, new is an operator with a very specific behavior: An expression with the new operator, first calls function operator new (i.e., this function) with the size of its type specifier as first argument, and if this is successful, it then automatically initializes or constructs the object (if needed). Finally, the expression evaluates as a pointer to the appropriate type.
代码里写的new是关键字,编译器根据实际情况调用new运算符。
代码里写下new关键字,编译器会: 1、调用operator new,也就是调用new运算符malloc,返回ptr。new运算符可以用户重载。 2、调用A::A()构造函数在ptr上初始化对象。 3、void*类型转化,返回对象的指针。
placement new
placement new也是new运算符的重载,多传入了一个参数void* ptr
,定义在#incldue<new>
中,对步骤一来说,直接返回ptr, 不再分配内存(用户已经分配好了,传入ptr)。
对象池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 #ifndef _ObjectPoolBase_hpp_ #define _ObjectPoolBase_hpp_ #include <stdlib.h> #include <assert.h> #include <mutex> #ifdef _DEBUG #ifndef xPrintf #include <stdio.h> #define xPrintf(...) printf(__VA_ARGS__) #endif #else #ifndef xPrintf #define xPrintf(...) #endif #endif template <class Type , size_t nPoolSzie>class CELLObjectPool { public : CELLObjectPool () { initPool (); } ~CELLObjectPool () { if (_pBuf) delete [] _pBuf; } private : class NodeHeader { public : NodeHeader* pNext; int nID; char nRef; bool bPool; private : char c1; char c2; }; public : void freeObjMemory (void * pMem) { NodeHeader* pBlock = (NodeHeader*)((char *)pMem - sizeof (NodeHeader)); xPrintf ("freeObjMemory: %llx, id=%d\n" , pBlock, pBlock->nID); assert (1 == pBlock->nRef); if (pBlock->bPool) { std::lock_guard<std::mutex> lg (_mutex) ; if (--pBlock->nRef != 0 ) { return ; } pBlock->pNext = _pHeader; _pHeader = pBlock; } else { if (--pBlock->nRef != 0 ) { return ; } delete [] pBlock; } } void * allocObjMemory (size_t nSize) { std::lock_guard<std::mutex> lg (_mutex) ; NodeHeader* pReturn = nullptr ; if (nullptr == _pHeader) { pReturn = (NodeHeader*)new char [sizeof (Type) + sizeof (NodeHeader)]; pReturn->bPool = false ; pReturn->nID = -1 ; pReturn->nRef = 1 ; pReturn->pNext = nullptr ; } else { pReturn = _pHeader; _pHeader = _pHeader->pNext; assert (0 == pReturn->nRef); pReturn->nRef = 1 ; } xPrintf ("allocObjMemory: %llx, id=%d, size=%d\n" , pReturn, pReturn->nID, nSize); return ((char *)pReturn + sizeof (NodeHeader)); } private : void initPool () { assert (nullptr == _pBuf); if (_pBuf) return ; size_t realSzie = sizeof (Type) + sizeof (NodeHeader); size_t n = nPoolSzie * realSzie; _pBuf = new char [n]; _pHeader = (NodeHeader*)_pBuf; _pHeader->bPool = true ; _pHeader->nID = 0 ; _pHeader->nRef = 0 ; _pHeader->pNext = nullptr ; NodeHeader* pTemp1 = _pHeader; for (size_t n = 1 ; n < nPoolSzie; n++) { NodeHeader* pTemp2 = (NodeHeader*)(_pBuf + (n* realSzie)); pTemp2->bPool = true ; pTemp2->nID = n; pTemp2->nRef = 0 ; pTemp2->pNext = nullptr ; pTemp1->pNext = pTemp2; pTemp1 = pTemp2; } } private : NodeHeader* _pHeader; char * _pBuf; std::mutex _mutex; }; template <class Type , size_t nPoolSzie>class ObjectPoolBase { public : void * operator new (size_t nSize) { return objectPool ().allocObjMemory (nSize); } void operator delete (void * p) { objectPool ().freeObjMemory (p); } template <typename ...Args> static Type* createObject (Args ... args) { Type* obj = new Type (args...); return obj; } static void destroyObject (Type* obj) { delete obj; } private : typedef CELLObjectPool<Type, nPoolSzie> ClassTypePool; static ClassTypePool& objectPool () { static ClassTypePool sPool; return sPool; } }; #endif #include "ObjectPoolBase.hpp"
这样也就能理解为什么从对象池中分配调用的是:Type* obj = new Type(args...)
而new的重载只有一个参数nSize
,因为nSize
就是new运算符的默认参数,分配了内存后再调用构造函数Type(args...)
初始化。
参考 new: https://blog.csdn.net/ly930156123/article/details/78855379 对象池实现:https://www.cnblogs.com/-citywall123/p/12726552.html