new和delete分配内存
2013-11-29 11:30
274 查看
一. 当内存用完时
当找不到足够大的连续的内存块用于存放对象时,一个称为new-handler的函数被调用,或者检查指向函数的指针,如果非0,则那个函数被调用;new-handler的缺省动作是抛出一个异常。通过包含new.h,然后以我们想调用的函数地址为参数,调用set_new_handler()函数,这样就替换了new-handler
二. 为什么要重载new和delete
1. 被new和delete使用的内存分配系统是为通用目的设计的,我们也需要创建、销毁一个特定类的非常多的对象,以至于这个运算成了速度瓶颈
2. 分配不同大小的内存,会导致内存碎片,因此可能还有内存,但是找不到足够大小的连续内存,因此需要定制内存分配器
3. 在嵌入式系统中,要求分配内存花费相同的时间,且不允许出现堆耗尽或出现很多碎片的情况,因此需要定制内存分配器
注释:当我们重载new时,可以改变的只是内存分配部分(delete类似)
三. 重载全局new和delete
运行结果:
注释:1. 因为类s有个虚函数,所以对象大小多出4个字节用于存放指向虚函数表的指针 2. 数组大小多出4个字节,用于存放数组的长度等信息 3. 这里使用printf和puts而不是iostream,因为当创建一个iostream对象时(全局cin、cout、cerr),他们会调用new分配内存,会进入死循环,printf不会调用new来初始化自己
四. 为一个类重载new和delete
为一个类重载new和delete时,不必说明是static,它默认为static成员函数
五. 为数组重载new和delete
六. 对象放置
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;
}
当找不到足够大的连续的内存块用于存放对象时,一个称为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;
}
相关文章推荐
- 使用new,delete实现内存分配联系
- C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- new和delete运算符用于动态分配和撤销内存的运算符
- C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free
- C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free
- c++:动态内存分配(new和delete的使用)
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- 内存分配方式,堆区,栈区,new/delete/malloc/free
- 动态内存分配(new)和释放(delete)
- new和delete运算符用于动态分配和撤销内存的运算符
- C/C++内存分配方式,栈区堆区 new/delete/malloc/free
- C++动态内存分配(new/new[]和delete/delete[])详解
- C/C++ 内存分配:malloc/calloc/realloc/free和new/delete
- 类和动态内存分配,类成员的动态内存分配,new,delete,定位new
- C/C++内存分配方式,栈区堆区 new/delete/malloc/free
- 内存分配方式,堆区,栈区,new/delete/malloc/free
- c/c++ 补漏之动态内存分配,malloc,free,new delete (一)
- C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free
- 动态内存分配- new/delete 和malloc/free的区别