您的位置:首页 > 其它

new和delete分配内存

2013-11-29 11:30 274 查看
一.  当内存用完时

当找不到足够大的连续的内存块用于存放对象时,一个称为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: