7_2_operator_new_delete.cpp
#include "hjcommon.hpp"
class A
{
public:
int m_num = 0;
A() { cout << "A." << endl; }
~A() { cout << "~A." << endl; }
static void *operator new(size_t size) // 重载系统的 new 操作符 ,应该是 static 的
{
A *pa = (A*)malloc(size);
cout << dec << "A operator new. size=" << size << ", 地址=" << hex << pa << endl;
return pa;
}
static void operator delete(void *phead) // 重载系统的 delete 操作符 ,应该是 static 的
{
cout << "A operator delete, 地址=" << hex << phead << endl;
free(phead);
}
static void *operator new[](size_t size) // 重载系统的 new[] 操作符 ,应该是 static 的
{
A *pa = (A*)malloc(size);
cout << "A operator new[]. size=" << size << ", 地址=" << hex << pa << endl;
return pa;
}
static void operator delete[](void *phead) // 重载系统的 delete[] 操作符 ,应该是 static 的
{
cout << "A operator delete[], 地址=" << hex << phead << endl;
free(phead);
}
};
int main_2_7_2(int argc, char *argv[])
{
/*
new A() 的时候,编译器调用顺序: operator new() -> malloc() -> A::A()
delete A 的时候,编译器调用顺序: A::~A() -> operator delete() -> free()
new A[2]() 的时候,编译器调用顺序: operator new[]() -> malloc() -> A::A() -> A::A()
delete[] A 的时候,编译器调用顺序: A::~A() -> A::~A() -> operator delete[]() -> free()
*/
A *pa1 = new A(); // new A(); 会将A中的成员清0(不是所有都清0) ,而 new A; 不会将成员变量清0
cout << hex << "pa1=" << pa1 << endl; // new单个对象时,编译器返回的地址与operator new() 返回的地址一样
pa1->m_num = 12;
delete pa1;
A *pa2 = ::new A(); // new前面的 :: 为全局操作符,表示调用系统的 operator new() 不调用类重载的。
cout << hex << "pa2=" << pa2 << endl;
::delete pa2;
cout << "---------------------------------" << endl;
A *pa3 = new A[3](); // 构造与析沟调用了3次,但是 operator new[]{} 和 operator delete[]() 只会调用一次
cout << hex << "pa3=" << pa3 << endl; // new数组时,编译器返回的地址与operator new[]() 返回的地址往后偏移了一段字节,这段地址保存着数组的长度信息
delete[] pa3;
A *pa4 = ::new A[3](); // 用系统的 operator new[]()
cout << hex << "pa4=" << pa4 << endl;
::delete[] pa4;
return 0;
}
7_3_内存池.cpp
#include "hjcommon.hpp"
#include <ctime>
class A
{
public:
static int m_newCount; // 每new一次类,计数+1
static int m_mallocCount; // 每malloc一次,计数+1
static void *operator new(size_t size)
{
A *tmp;
if (m_freePos==nullptr)
{
size_t realsize = m__trunkCount * size;
m_freePos = reinterpret_cast<A*>(new char[realsize]);
tmp = m_freePos;
// 将分配的 m__trunkCount 个内存链起来
for (; tmp!=&m_freePos[m__trunkCount-1]; ++tmp)
{
tmp->next = tmp+1;
}
tmp->next = nullptr; // 链表最后一个节点指向空
++m_mallocCount;
// cout << dec << "malloc 内存块 <" << m_mallocCount << "> 首地址=" << hex << m_freePos << endl;
}
tmp = m_freePos;
m_freePos = m_freePos->next; // 链向下一个节点,供下次 new A 使用
++m_newCount;
// cout << dec << "new 内存块 <" << m_mallocCount << ">, m_newCount=" << m_newCount << ", 此次new分配的地址=" << hex << tmp << endl;
return tmp;
}
static void operator delete(void *phead)
{
A *pa = static_cast<A*>(phead);
pa->next = m_freePos;
m_freePos = pa;
}
//private:
A *next = nullptr;
static A *m_freePos; // 总是指向一块可以分配出去的内存的首地址
static int m__trunkCount; // 一次分配多少倍的该类内存
};
int A::m_newCount = 0;
int A::m_mallocCount = 0;
A *A::m_freePos = nullptr;
int A::m__trunkCount = 5;
int main_2_7_3(int argc, char *argv[])
{
// 内存池:一次分配一块大内存,使用时一点一点给你。 减少 malloc 次数,减少内存浪费,提升运行效率,因为malloc本身速度就很快,所以提升的并不会很明显。
// 类的内存池实现:
// A *pa1 = new A();
// A *pa2 = new A();
// A *pa3 = new A();
// A *pa4 = new A();
// A *pa5 = new A();
// cout << (pa5->next==nullptr) << ", " << (pa5->m_freePos==nullptr) << endl; // 1, 1
// A *pa6 = new A();
// cout << (pa5->next==nullptr) << ", " << (pa5->m_freePos==nullptr) << endl; // 1, 0
// delete pa5; // 只有当开辟了新内存块且这时删除前一内存块的某个之后,前一个内存块与后一个内存块才会链接起来。
// A *pa7 = new A();
// cout << (pa5->next==nullptr) << ", " << (pa5->m_freePos==nullptr) << endl; // 1, 0
clock_t start, end; // 计算耗时(毫秒)的另一种方式,需要 #include <ctime>
start = clock(); // ubuntu中时间单位为微秒, windows中此函数时间单位为毫秒。。
auto kai = getTimePoint();
for (int i=0; i<500'0000; ++i) // 500'0000 表示五百万 c++11新写法
{
A *pa = new A();
}
end = clock();
// malloc次数=10000, new次数=5000000, 耗时=36869, 0.0370048 内存块大小500时
// malloc次数=0, new次数=0, 耗时=254440, 0.261108 原装malloc时
cout << "malloc次数=" << A::m_mallocCount << ", new次数=" << A::m_newCount << ", 耗时=" << end-start << ", " << calcTimeCounts(kai) << endl;
return 0;
}
7_4_嵌入式指针.cpp
#include "hjcommon.hpp"
class A
{
public:
struct obj
{
struct obj *next; // 嵌入式指针, 含有内部类的空类 sizeof(A) 也是 1
};
};
int main_2_7_4(int argc, char *argv[])
{
// 嵌入式指针:借用类对象的地址作为链表的 next ,要求 sizeof(class) >= sizeof(void *)
cout << sizeof(void *) << endl;
return 0;
}
7_5_全局new_delete.cpp
#include "hjcommon.hpp"
/* 无法 static 。。
void *operator new(size_t size)
{
cout << "全局new. size=" << size << endl;
return malloc(size);
}
void operator delete(void *phead)
{
cout << "全局delete." << endl;
free(phead);
}
void *operator new[](size_t size)
{
cout << "全局new[].size=" << size << endl;
return malloc(size);
}
void operator delete[](void *phead)
{
cout << "全局delete[]." << endl;
free(phead);
}
*/
class A
{
public:
int m_num;
A() : m_num(0) { cout << "no arg." << endl; }
A(int num) : m_num(num) { cout << "one arg." << endl; }
~A() { cout << "destructor." << endl; }
static void *operator new(size_t size, void *phead) // 定位new时,重载类的new
{
cout << dec << "A placement new. size=" << size << ", 地址=" << hex << phead << endl;
return phead;
}
static void *operator new(size_t size, int num, String str) // opearator new() 函数重载,注意第一个参数必须还是 size_t
{
A *pa = (A*)malloc(size);
cout << dec << "A operator new. size=" << size << ", 地址=" << hex << pa << dec << ", " << num << ", " << str << endl;
return pa;
}
static void operator delete(void *phead) // 定位new了就无法再重载类的delete
{
cout << "A operator delete, 地址=" << hex << phead << endl;
free(phead);
}
};
int main_2_7_5(int argc, char *argv[])
{
int *pi = new int(1);
char *pc = new char[10];
delete pi;
delete[] pc;
// 类中重载的new delete 会优先级会高于全局的new delete
// 定位new(placement new) 功能 : 在已经分配的原始内存中初始化一个对象(可理解为调用该对象的构造函数) ,不会额外分配内存
void *mem = new char[sizeof(A)];
A *pa1 = new(mem) A(); // 定位new 调用格式: new (内存地址)A()
A *pa2 = new(mem) A(1);
cout << hex << mem << ", " << pa1 << ", " << pa2 << endl;
// 定位new 释放内存
pa1->~A(); // 手动效用析沟函数, 一般析沟函数可以手动调用,但构造函数一般不能手动调用。
pa2->~A();
delete[] (void *)pa1; // 删除定位new 调用的是全局 operator delete() 非类的 operator delete
delete[] (void *)pa2;
// 类的 opearator new() 函数重载,注意第一个参数必须还是 size_t
A *pa3 = new(3, "some") A(3);
delete pa3;
return 0;
}