2_7 operator new、operator delete、内存池、嵌入式指针

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值