new和delete分配内存

本文详细解析了C++中内存管理的关键概念,包括如何处理内存耗尽情况、重载new和delete函数以优化内存分配、为特定类和数组重载这些操作符、以及对象放置策略在嵌入式系统中的应用。文章还展示了通过重载运算符new和delete来定制内存分配器,以及在不同场景下如何灵活地控制对象的内存布局。

一.  当内存用完时

当找不到足够大的连续的内存块用于存放对象时,一个称为new-handler的函数被调用,或者检查指向函数的指针,如果非0,则那个函数被调用;new-handler的缺省动作是抛出一个异常。通过包含new.h,然后以我们想调用的函数地址为参数,调用set_new_handler()函数,这样就替换了new-handler

#include <iostream>
#include <stdlib.h>
#include <new.h>
using namespace std;

void out_of_memory()
{
	cerr << "memory exhausted!" << endl;
	exit(1);
}

int main()
{
	set_new_handler(out_of_memory);

	while(1)
		new int[100];

	system("pause");
	return 1;
}


二. 为什么要重载new和delete

1. 被new和delete使用的内存分配系统是为通用目的设计的,我们也需要创建、销毁一个特定类的非常多的对象,以至于这个运算成了速度瓶颈

2. 分配不同大小的内存,会导致内存碎片,因此可能还有内存,但是找不到足够大小的连续内存,因此需要定制内存分配器

3. 在嵌入式系统中,要求分配内存花费相同的时间,且不允许出现堆耗尽或出现很多碎片的情况,因此需要定制内存分配器

注释:当我们重载new时,可以改变的只是内存分配部分(delete类似)

三. 重载全局new和delete

#include <stdio.h>
#include <stdlib.h>

void* operator new(size_t sz)
{
	printf("operator new: %d bytes\n", sz);
	void* m = malloc(sz);
	if(!m) puts("out of memory");
	return m;
}

void operator delete(void* m)
{
	puts("operator delete");
	free(m);
}

class s
{
	int i[100];
public:
	s()
	{
		puts("s::s();");
	}
	~s()
	{
		puts("s::~s();");
	}
	virtual int count()
	{
		return 1;
	}
};

int main()
{
	puts("creating & destorying an int");
	int* p = new int(88);
	delete p;

	puts("creating & destorying an s");
	s* S = new s();
	delete S;

	puts("creating & destorying s[3]");
	s* SA = new s[3];
	delete []SA;

	system("pause");
	return 1;
}

运行结果:

注释:1. 因为类s有个虚函数,所以对象大小多出4个字节用于存放指向虚函数表的指针  2. 数组大小多出4个字节,用于存放数组的长度等信息  3. 这里使用printf和puts而不是iostream,因为当创建一个iostream对象时(全局cin、cout、cerr),他们会调用new分配内存,会进入死循环,printf不会调用new来初始化自己

四. 为一个类重载new和delete

为一个类重载new和delete时,不必说明是static,它默认为static成员函数

#include <stddef.h>
#include <fstream>
using namespace std;
ofstream out("framis.out");

class framis
{
	char c[10];
	static unsigned char pool[];
	static unsigned char malloc_map[];
public:
	enum{PSIZE = 100};
	framis()
	{
		out << "framis()\n";
	}
	~framis()
	{
		out << "~framis()\n";
	}
	void* operator new(size_t);
	void operator delete(void*);
};

unsigned char framis::pool[PSIZE * sizeof(framis)];
unsigned char framis::malloc_map[PSIZE] = {0};

void* framis::operator new(size_t)
{
	for (int i = 0; i < PSIZE; i++)
	{
		if (!malloc_map[i])
		{
			out << "using block " << i << " ...";
			malloc_map[i] = 1;
			return pool + (i * sizeof(framis));
		}
	}
	out << "out of memory" << endl;
	return 0;
}

void framis::operator delete(void* m)
{
	if (!m) return;
	unsigned long block = (unsigned long)m - (unsigned long)pool;
	block /= sizeof(framis);
	out << "freeing block " << block << endl;
	malloc_map[block]  = 0;
}

int main()
{
	framis* f[framis::PSIZE];
	for (int i = 0; i < framis::PSIZE; i++)
	{
		f[i] = new framis;
	}
	new framis; //out of memory
	
	delete f[10];
	f[10] = 0;
	
	framis* X = new framis;
	delete X;

	for (int j = 0; j < framis::PSIZE; j++)
	{
		delete f[j];
	}

	system("pause");
	return 1;
}


五. 为数组重载new和delete


#include <new.h>
#include <fstream>
using namespace std;
ofstream trace("newarray.out");

class widget
{
	int i[10];
public:
	widget()
	{
		trace << "*";
	}
	~widget()
	{
		trace << "~";
	}
	void* operator new(size_t sz)
	{
		trace << "widget::new: " << sz << " bytes" << endl;
		return ::new char[sz];
	}
	void operator delete(void* p)
	{
		trace << "widget::delete" << endl;
		::delete []p;
	}
	void* operator new[](size_t sz)
	{
		trace << "widget::new[] : " << sz << " bytes" << endl;
		return ::new char[sz];
	}
	void operator delete[](void* p)
	{
		trace << "widget::delete[]" << endl;
		::delete []p;
	}
};

int main()
{
	trace << "new widget" << endl;
	widget* w = new widget;
	trace << "\ndelete widget" << endl;
	delete w;
	trace << "\nnew widget[25]" << endl;
	widget* wa = new widget[25];
	trace << "\ndelete widget[25]" << endl;
	delete []wa;

	system("pause");
	return 1;
}


六. 对象放置

1. 可能想在内存的指定位置放置一个对象,这对于嵌入式系统特别重要

2. 调用new时,可以从不同的内存分配器中进行选择

这两种需求,都可以通过相同的机制实现,重载运算符new时,带多于一个参数,第一个参数是对象长度,它是在内部计算并由编译器传递。其他的参数可以有我们定义:一个放置对象的地址、一个对内存分配的函数或对象的引用、或其他方便的任何设置


#include <stddef.h>
#include <iostream>
using namespace std;

class X
{
public:
	int i;
public:
	X(int I = 0)
	{
		i = I;
	}
	~X()
	{
		cout << "X::~X()" << endl;
	}
	void* operator new(size_t, void* loc)
	{
		return loc;
	}
};

int main()
{
	int l[10];
	X* xp = new(l) X(88);
	cout << xp->i << endl;
	xp->X::~X(); //explicit destructor call

	system("pause");
	return 1;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值