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<A *>(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()"<<endl;
}
~A(){
cout<<"~A()"<<endl;
}
};
void * A::operator new(size_t size){//size == sizeof(A),一个字节
cout<<"A::operator new()"<<endl;
A *p = (A *)malloc(size);
return p;
}
void * A::operator delete(void *p){
cout<<"A::operator delete()"<<endl;
free(p);
}
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()"<<endl;
}
~A(){
cout<<"~A()"<<endl;
}
};
//size == 7,sizeof(A) * 3 + 4
//多出4个字节记录数组大小,知道调用构造函数和析构函数次数。
void * A::operator new[](size_t size){
cout<<"A::operator new[]()"<<endl;
A *p = (A *)malloc(size);
return p;
}
void * A::operator delete[](void *p){
cout<<"A::operator delete[]()"<<endl;
free(p);
}
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一次+1
static int m_iMallocCount; //统计malloc次数,每malloc一次+1
A()
{
// 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<A *>(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<A *>(p))->next = m_FreePosi;
m_FreePosi = static_cast<A *>(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一次+1
static int m_iMallocCount; //统计malloc次数,每malloc一次+1
private:
A *next;
static A *m_FreePosi; //指向一块分配出去的内存首地址
static int m_sTrunkCount; //一次分配多少倍该类的内存
};
//#define MYMEMPOOL
void *A::operator new(size_t size)
{
#ifdef MYMEMPOOL
A *p = (A *)malloc(size);
return p;
#endif
A *tmplink;
if (m_FreePosi == nullptr)
{
m_sTrunkCount *= 2;
size_t realsize = size * m_sTrunkCount;
m_FreePosi = reinterpret_cast<A *>(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 MYMEMPOOL
free(p);
return;
#endif
(static_cast<A *>(p))->next = m_FreePosi;
m_FreePosi = static_cast<A *>(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一次+1
static int m_iMallocCount; //统计malloc次数,每malloc一次+1
A()
{
// 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<A *>(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<A *>(p))->next = m_FreePosi;
m_FreePosi = static_cast<A *>(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一次+1
static int m_iMallocCount; //统计malloc次数,每malloc一次+1
private:
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 MYMEMPOOL
void *A::operator new(size_t size)
{
#ifdef MYMEMPOOL
A *p = (A *)malloc(size);
return p;
#endif
A *tmplink;
if (m_FreePosi == nullptr)
{
m_sTrunkCount *= 2;
size_t realsize = size * m_sTrunkCount;
m_FreePosi = reinterpret_cast<A *>(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 MYMEMPOOL
free(p);
return;
#endif
(static_cast<A *>(p))->next = m_FreePosi;
m_FreePosi = static_cast<A *>(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<<mytest.m_i<<endl;
TestEP::obj *ptmp = (TestEP::obj *)&mytest;
ptmp->next = nullptr;
cout<<mytest.m_i<<endl;
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;
};
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()"<<endl;
}
PLA(int tmp):m_a(tmp){
cout<<"PLA(int)"<<endl;
}
~PLA()
cout<<"~PLA()"<<endl;
}
};
//先分配内存
void *p1 = (void *)new char[sizeof(PLA)];
//定位new,调用无参构造函数,不额外分配内存
PLA *po1 = new(p1) PLA();
po1->~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();//函数,内部没有调用malloc
PLA::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;
}