class A {
public:
};A *pa = new A();
A *pa2 = new A;
(1)空类,两者无区别;
(2)若类A有成员变量(int m_i;),有括号初始化为0,无括号随机值。
(3)若类A有构造函数(A(){}),初始化工作交给构造函数自己做(构造函数空,随机值)。
int *p1 = new int;//随机值
int *p2 = new int();//0
int *p3 = new int(100);//100
new关键字或者操作符,主要做了两件事。
调用operator new()函数(内部调用了malloc()函数)和调用类的构造函数。
A *pa = new A(); //操作数operator new(); //函数malloc(); //c风格函数分配内存A::A(); //有构造函数就调用构造函数
delete pa;A::~A(); //存在析构函数,则先调用析构函数operator delete(); //函数free(); //c风格函数释放内存
new与malloc区别:
(1)new是关键字/操作符,malloc是函数;
(2)new对象时,分配内存+调用构造函数(若存在);
(3)new A(),可以成员变量初始化。
delete与free区别:
(1)delete是关键字/操作符,free是函数;
(2)delete对象时,释放内存+调用析构函数(若存在);
new最终通过调用malloc来分配内存。
char *p = new char[10]; //new char[10](0);
memset(p, 0, 10);
delete[] p;
malloc分配内存周围记录了很多其他内容,记录分配的字节数等。
free内存块,包括合并数据块、登记空闲块的大小、设置空闲块首位的一些标记以方便下次分配等。
malloc分配可能的内存布局:
记录分配字节数(4字节)
Debug模式下可能的调试信息(几十字节)
实际分配字节
其他必要信息,边界调整的字节填充等(几十字节)
回收内存时内存尾标记的尾信息(4字节)
A *pa = new A(); //操作数operator new(); //函数malloc(); //c风格函数分配内存A::A(); //有构造函数就调用构造函数
等价于
void *tmp = operator new(sizeof(A));
A *pa = static_cast(tmp);
pa->A::A();
delete pa;A::~A(); //存在析构函数,则先调用析构函数operator delete(); //函数free(); //c风格函数释放内存
等价于
pa->A::A();
operator delete(pa);
class A{
public://无static似乎也行(估计编译器内部处理)static void * operator new(size_t size);static void * operator delete(void *p);A(){cout<<"A()"<cout<<"~A()"<//size == sizeof(A),一个字节cout<<"A::operator new()"<cout<<"A::operator delete()"<
A *pa1 = new A();
delete pa1;//::作用域运算符
//调用全局new和delete关键字
A *pa2 = ::new A();
::delete pa2;
class A{
public://无static似乎也行(估计编译器内部处理)static void * operator new[](size_t size);static void * operator delete[](void *p);A(){cout<<"A()"<cout<<"~A()"<cout<<"A::operator new[]()"<cout<<"A::operator delete[]()"<
A *pa1 = new A[3]();
delete[] pa1;//输出
/*
A::operator new[]()
A()
A()
A()
~A()
~A()
~A()
A::operator delete[]()
*/
malloc频繁分配小块内存时,浪费明显。
内存池解决的主要问题:
内存池的实现原理是用malloc申请一大块内存,使用时一点点分配。不够时,重新分配更大一块内存,然后一点点分配。涉及到内存如何一小块分割和回收问题。
#include
#include
#include
using namespace std;namespace _n1
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);A(){cout << "A()\n";}~A(){cout << "~A()\n";}};void *A::operator new(size_t size){cout << "new\n";//传统实现A *p = (A *)malloc(size);return p;}void A::operator delete(void *p){cout << "delete\n";//传统实现free(p);}
}namespace _n2
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);static int m_iCount; //分配计数统计,每new一次+1static int m_iMallocCount; //统计malloc次数,每malloc一次+1A(){// cout << "A()\n";}~A(){// cout << "~A()\n";}private:A *next;static A *m_FreePosi; //指向一块分配出去的内存首地址static int m_sTrunkCount; //一次分配多少倍该类的内存};void *A::operator new(size_t size){// cout << "new\n";A *tmplink;if (m_FreePosi == nullptr){size_t realsize = size * m_sTrunkCount;m_FreePosi = reinterpret_cast(new char[realsize]);for (tmplink = m_FreePosi; tmplink != &m_FreePosi[m_sTrunkCount - 1]; ++tmplink)tmplink->next = tmplink + 1;tmplink->next = nullptr;++m_iMallocCount;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;++m_iCount;return tmplink;}void A::operator delete(void *p){// cout << "delete\n";(static_cast(p))->next = m_FreePosi;m_FreePosi = static_cast(p);}int A::m_iCount = 0;int A::m_iMallocCount = 0;A *A::m_FreePosi = nullptr;int A::m_sTrunkCount = 5 * 100;
}namespace _n3
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);static int m_iCount; //分配计数统计,每new一次+1static int m_iMallocCount; //统计malloc次数,每malloc一次+1private:A *next;static A *m_FreePosi; //指向一块分配出去的内存首地址static int m_sTrunkCount; //一次分配多少倍该类的内存};//#define MYMEMPOOLvoid *A::operator new(size_t size){
#ifdef MYMEMPOOLA *p = (A *)malloc(size);return p;
#endifA *tmplink;if (m_FreePosi == nullptr){m_sTrunkCount *= 2;size_t realsize = size * m_sTrunkCount;m_FreePosi = reinterpret_cast(new char[realsize]);for (tmplink = m_FreePosi; tmplink != &m_FreePosi[m_sTrunkCount - 1]; ++tmplink)tmplink->next = tmplink + 1;tmplink->next = nullptr;++m_iMallocCount;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;++m_iCount;return tmplink;}void A::operator delete(void *p){
#ifdef MYMEMPOOLfree(p);return;
#endif(static_cast(p))->next = m_FreePosi;m_FreePosi = static_cast(p);}int A::m_iCount = 0;int A::m_iMallocCount = 0;A *A::m_FreePosi = nullptr;int A::m_sTrunkCount = 5 * 100;
}int main()
{if (0){_n1::A *pa = new _n1::A();delete pa;cout << sizeof(_n1::A) << endl;}if (0){clock_t start = clock();for (int i = 0; i < 5000000; i++)_n2::A *pa = new _n2::A();// delete pa;clock_t end = clock();cout << "m_iCount: " << _n2::A::m_iCount << endl;cout << "m_iMallocCount: " << _n2::A::m_iMallocCount << endl;cout << "time: " << (end - start) / 1000.0 << endl;}if (1){clock_t start = clock();for (int i = 0; i < 5000000; i++)_n3::A *pa = new _n3::A();clock_t end = clock();cout << "m_iCount: " << _n3::A::m_iCount << endl;cout << "m_iMallocCount: " << _n3::A::m_iMallocCount << endl;cout << "time: " << (end - start) / 1000.0 << endl;}cout << "Over!\n";return 0;
}
#include
#include
#include
using namespace std;namespace _n1
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);A(){cout << "A()\n";}~A(){cout << "~A()\n";}};void *A::operator new(size_t size){cout << "new\n";//传统实现A *p = (A *)malloc(size);return p;}void A::operator delete(void *p){cout << "delete\n";//传统实现free(p);}
}namespace _n2
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);static int m_iCount; //分配计数统计,每new一次+1static int m_iMallocCount; //统计malloc次数,每malloc一次+1A(){// cout << "A()\n";}~A(){// cout << "~A()\n";}private:A *next;static A *m_FreePosi; //指向一块分配出去的内存首地址static int m_sTrunkCount; //一次分配多少倍该类的内存};void *A::operator new(size_t size){// cout << "new\n";A *tmplink;if (m_FreePosi == nullptr){size_t realsize = size * m_sTrunkCount;m_FreePosi = reinterpret_cast(new char[realsize]);for (tmplink = m_FreePosi; tmplink != &m_FreePosi[m_sTrunkCount - 1]; ++tmplink)tmplink->next = tmplink + 1;tmplink->next = nullptr;++m_iMallocCount;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;++m_iCount;return tmplink;}void A::operator delete(void *p){// cout << "delete\n";(static_cast(p))->next = m_FreePosi;m_FreePosi = static_cast(p);}int A::m_iCount = 0;int A::m_iMallocCount = 0;A *A::m_FreePosi = nullptr;int A::m_sTrunkCount = 5 * 100;
}namespace _n3
{class A{public:static void *operator new(size_t size);static void operator delete(void *p);static int m_iCount; //分配计数统计,每new一次+1static int m_iMallocCount; //统计malloc次数,每malloc一次+1private:A *next;static A *m_FreePosi; //指向一块分配出去的内存首地址static int m_sTrunkCount; //一次分配多少倍该类的内存//释放内存池class GC{public:~GC(){cout << "~GC()\n";while (A::m_FreePosi){A *tmp = A::m_FreePosi;free((void *)A::m_FreePosi);A::m_FreePosi = tmp->next;}}};static GC gc;};//#define MYMEMPOOLvoid *A::operator new(size_t size){
#ifdef MYMEMPOOLA *p = (A *)malloc(size);return p;
#endifA *tmplink;if (m_FreePosi == nullptr){m_sTrunkCount *= 2;size_t realsize = size * m_sTrunkCount;m_FreePosi = reinterpret_cast(new char[realsize]);for (tmplink = m_FreePosi; tmplink != &m_FreePosi[m_sTrunkCount - 1]; ++tmplink)tmplink->next = tmplink + 1;tmplink->next = nullptr;++m_iMallocCount;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;++m_iCount;return tmplink;}void A::operator delete(void *p){
#ifdef MYMEMPOOLfree(p);return;
#endif(static_cast(p))->next = m_FreePosi;m_FreePosi = static_cast(p);}int A::m_iCount = 0;int A::m_iMallocCount = 0;A *A::m_FreePosi = nullptr;int A::m_sTrunkCount = 5 * 100;A::GC A::gc;
}int main()
{if (0){_n1::A *pa = new _n1::A();delete pa;cout << sizeof(_n1::A) << endl;//_n1::A a;}if (0){clock_t start = clock();for (int i = 0; i < 5000000; i++)_n2::A *pa = new _n2::A();// delete pa;clock_t end = clock();cout << "m_iCount: " << _n2::A::m_iCount << endl;cout << "m_iMallocCount: " << _n2::A::m_iMallocCount << endl;cout << "time: " << (end - start) / 1000.0 << endl;}if (0){clock_t start = clock();for (int i = 0; i < 5000000; i++)_n3::A *pa = new _n3::A();clock_t end = clock();cout << "m_iCount: " << _n3::A::m_iCount << endl;cout << "m_iMallocCount: " << _n3::A::m_iMallocCount << endl;cout << "time: " << (end - start) / 1000.0 << endl;}cout << "Over!\n";return 0;
}
类A中存在成员变量A *next;当一个空闲内存块分配出去后,next指向无实际意义(不需要了),可以被覆盖,另作他用,节省字节。
next占用4个字节,sizeof(A)必须大于等于4。
#include
#include
#include
using namespace std;class TestEP
{
public:int m_i = 5;int m_j;struct obj{struct obj *next;};
};int main()
{cout << sizeof(TestEP) << endl;TestEP mytest;cout<next = nullptr;cout<
#include
#include
#include
using namespace std;//专门的内存池类或内存分配器
//使用本类的类sizeof()必须大于等于4
class myallocator
{
public://释放内存池~myallocator(){while (m_FreePosi){obj *tmp = m_FreePosi;m_FreePosi = m_FreePosi->next;free((void *)tmp);}}//分配内存接口void *allocate(size_t size){obj *tmplink;if (m_FreePosi == nullptr){size_t realsize = m_sTrunkCout * size;m_FreePosi = (obj *)malloc(realsize);tmplink = m_FreePosi;for (int i = 0; i < m_sTrunkCout - 1; ++i){tmplink->next = (obj *)((char *)tmplink + size);tmplink = tmplink->next;}tmplink->next = nullptr;m_sTrunkCout *= 2;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;return tmplink;}//释放内存接口void deallocate(void *p){((obj *)p)->next = m_FreePosi;m_FreePosi = (obj *)p;}private://类内结构,只能类内使用struct obj{struct obj *next; // next就是嵌入式指针};int m_sTrunkCout = 5;obj *m_FreePosi = nullptr;
};class A
{
public://必须保证sizeof(A)凑够4字节int m_i;int m_j;public:static myallocator myalloc;static void *operator new(size_t size){return myalloc.allocate(size);}static void operator delete(void *p){myalloc.deallocate(p);}
};
myallocator A::myalloc;int main()
{{cout << sizeof(myallocator) << endl;cout << sizeof(A) << endl;A *mypa[100];for (int i = 0; i < 15; ++i){mypa[i] = new A();printf("%p\n", mypa[i]);}for (int i = 0; i < 15; ++i){delete mypa[i];}}cout << "Over!\n";return 0;
}
#include
#include
#include
using namespace std;//专门的内存池类或内存分配器
//使用本类的类sizeof()必须大于等于4
class myallocator
{
public://释放内存池~myallocator(){while (m_FreePosi){obj *tmp = m_FreePosi;m_FreePosi = m_FreePosi->next;free((void *)tmp);}}//分配内存接口void *allocate(size_t size){obj *tmplink;if (m_FreePosi == nullptr){size_t realsize = m_sTrunkCout * size;m_FreePosi = (obj *)malloc(realsize);tmplink = m_FreePosi;for (int i = 0; i < m_sTrunkCout - 1; ++i){tmplink->next = (obj *)((char *)tmplink + size);tmplink = tmplink->next;}tmplink->next = nullptr;m_sTrunkCout *= 2;}tmplink = m_FreePosi;m_FreePosi = m_FreePosi->next;return tmplink;}//释放内存接口void deallocate(void *p){((obj *)p)->next = m_FreePosi;m_FreePosi = (obj *)p;}private://类内结构,只能类内使用struct obj{struct obj *next; // next就是嵌入式指针};int m_sTrunkCout = 5;obj *m_FreePosi = nullptr;
};#define DECLARE_POOL_ALLOC() \
public: \static void *operator new(size_t size) \{ \return myalloc.allocate(size); \} \static void operator delete(void *p) \{ \myalloc.deallocate(p); \} \static myallocator myalloc;#define IMPLEMENT_POOL_ALLOC(classname) \myallocator classname::myalloc;class A
{DECLARE_POOL_ALLOC();public://必须保证sizeof(A)凑够4字节int m_i;int m_j;
};
IMPLEMENT_POOL_ALLOC(A);int main()
{{cout << sizeof(myallocator) << endl;cout << sizeof(A) << endl;A *mypa[100];for (int i = 0; i < 15; ++i){mypa[i] = new A();printf("%p\n", mypa[i]);}for (int i = 0; i < 15; ++i){delete mypa[i];}}cout << "Over!\n";return 0;
}
//重载全局operator new
void * operator new(size_t size){return malloc(size);
}//重载全局operator new[]
void * operator new[](size_t size){return malloc(size);
}//重载全局operator delete
void * operator delete(void * p){return free(p);
}//重载全局operator delete[]
void * operator delete[](void * p){return free(p);
}int *pi = new int(12);
delete pi;
char *pc = new char[10](0);
delete[] pc;A *p = new A();
delete p;
A *pa = new A[3]();
delete[] pa;
一般重载类中operator new/delete ([])。
placement new无对应的placement delete,在已经分配的原始内存中初始化一个对象。
new(地址) 类类型(参数);
class PLA{
public:int m_a;PLA():m_a(0){cout<<"PLA()"<cout<<"PLA(int)"<~PLA();//根据需要调用析构函数
delete[](void *)po1;//释放内存
//delete[] p1;//同上//先分配内存
void *p2 = (void *)new char[sizeof(PLA)](0);
//定位new,调用有参构造函数,不额外分配内存
PLA *po2 = new(p2) PLA(12);
po2->~PLA();//根据需要调用析构函数
delete[](void *)po2;//释放内存
//delete[] p2;//同上
定位new调用关系
PLA *pa = new(已经分配好的内存首地址) PLA();//定位new操作符operator new();//函数,内部没有调用mallocPLA::PLA();//调用构造函数
定位new调用的operator new操作符的重载代码。
public:void * operator new(size_t, void *p){//多一个p,指向已经分配好的内存首地址return p;}
第一个参数固定size_t(sizeof(对象)),其他参数指定。
//无内存分配,无类构造函数调用
PLA *po2 = new(1234, 56) PLA(12);public://第一个参数,系统默认传递sizeof(PLA)void * operator new(size_t size, int t1, int t2){return NULL;}
会出现警告:void *PLA::operator new(size_t, int, int)未找到匹配的删除运算符。
可以增加对应的operator delete重载以避免警告(非必需)。
public:void operator delete(void* p, int t1, int t2){return;}