c++的new和delete
来源:互联网 发布:电影票电子码软件 编辑:程序博客网 时间:2024/04/29 06:12
C++的new是语言自定义的操作符,这个操作符的行为包含两件事,而且你不能改变:
第一件事:调用operator new( )分配内存。所以通常说的重载new其实重载的是operator new( )这个函数,你无法重载new操作符。
第二件事:调用你要new的对象的所属类的构造函数初始化第一步中分配的内存。
delete操作符也是类似,它先调用析构函数,然后调用operator delete( )释放内存。
操作符new和delete只能这样调用:
new(可能的参数,也可以是空) 内置数据类型或类;
delete 一个指针;
new[]、delete[]和new、delete是极其类似的,所以这里只说明new和delete。
这是头文件<new>里operator new()和operator delete()的所有声明(当然是我去除旁枝末节之后的),这些都是全局的,不包含在namespace std里,而且默认编译器会自动包含头文件<new>,并不需要显式include:
void* operator new(std::size_t) throw(std::bad_alloc);void operator delete(void*) throw();void* operator new(std::size_t, const std::nothrow_t&) throw();void operator delete(void*, const std::nothrow_t&) throw();inline void* operator new(std::size_t, void *p) throw() {return p;}inline void operator delete(void*, void*) throw() { }
最后两个称为placement版,是从p所指向的内存区域分配内存,p可以是一个char数组、int数组之类的。这两个是内联的,由于内联函数只能有一个定义,所以你无法在全局里重载它们。而且,由于你无法给delete操作符传递第二个参数(delete操作符只有一种调用方式),所以placement operator delete()是无法通过delete操作符调用的,这意味着,我们只能显式的调用析构函数和placement operator delete( ),placement operator delete( )也是空的,你给它传递什么参数都无所谓。这两个函数并没有分配内存的操作,所以它不会throw异常。
再说operator new( )的第一个参数,这个参数是编译器要分配内存的大小,是由编译器计算并且隐式传递的,并不需要我们插手。在编译器的内部实现中,传入new的尺寸值可能是所需内存的大小s加上一个delta。这个delta量是编译器的内部实现所定义的某种额外开销。为什么delete操作符不需要第二个尺寸参数呢?因为系统“记住”了分配内存的大小。
这里有两个版本的operator new( ),区别在于是否可能throw异常。namespace std里定义了nothrow_t和一个nothrow_t类型的变量:
struct nothrow_t { };extern const nothrow_t nothrow;
operator new( ) 和operator delete( )的重载
我们可以将这两个函数重载为全局的,也可以重载为类的成员函数。
如果要把它们重载为全局的,最好不要覆盖默认的operator new() 和operator delete(),可以多加一个参数来避免覆盖默认的版本,例如:
void *operator new(size_t n,int m){<span style="white-space:pre"></span>return ::operator new(n);}
是的,正如你看到一样,重载后的版本可以带多个参数,后面会详细说明。
如果覆盖了默认的operator new() ,不要在里面调用::operator new(),而应调用malloc(),否则就会发生递归调用。
如果将它们重载为类的成员函数,它们默认成为static的,这很明显,调用它们的时候构造函数都没有调用,this指针还不存在。但我们不妨手动给它加上static关键字。
new操作符后面可以有一个括号,可以带很多参数。你可以将operator new()重载为多个参数的,只要第一个参数是size_t类型的就OK了。实际上,placement operator new()也不过是operator new()的一个重载版本。
operator delete()也可以进行重载,不过我们还是无法通过delete操作符来调用有多个参数的operator delete()。
异常
如果new操作符不能分配出内存,会发生什么呢?
默认情况下,抛出一个bad_alloc异常对象;如果我们自定义了内存耗尽时的处理方法(new_handler),则会执行这个方法。定义完处理方法后需要用set_new_handler()来登记。set_new_handler()是定义在namespace std里的,它返回旧的handler:new_handler set_new_handler(new_handler) throw();。
动态分配一个二维数组
int x = 3, y = 4;int **p = new int*[x];//创建一个动态 int* 型数组for (int i = 0; i < x; ++i)p[i] = new int [y]; //再创建一个动态 int 型数组 for (int i = 0; i < x; ++i){ delete[] p[i];//由里至外,进行释放内存。 p[i] = NULL;//不要忘记,释放空间后p[i]不会自动指向NULL值,还将守在原处,只是释放内存而已,仅此而已。}delete []p;p = NULL;
如果要使二维数组占用一块连续内存,可以这样:
要用的方便,可以在array上加定义一个指针变量。
int *array1 = new int[x*y];int **array2;array2 = new int *[x];for(int i=0; i<x; ++i) array2[i] = array1 + i*y;
用起来还是array2[i][j]。
delete[] array1;delete[] array2;
gcc中new、new[]、delete、delete[]的源码
// new的主要工作就是调用mallocvoid* operator new(size_t sz) throw(std::bad_alloc){ void *p; /* malloc(0) is unpredictable; avoid it. */ if(sz == 0) sz = 1; p = (void *)malloc(sz); while(p == 0) { new_handler handler = __new_handler; if(!handler) throw bad_alloc(); handler(); p = (void *)malloc(sz); } return p;}// new[]的内容就是调用newvoid* operator new[] (size_t sz) throw(std::bad_alloc){ return ::operator new(sz);}// delete的内容是调用freevoid operator delete (void *ptr) throw(){ if(ptr) free(ptr);}// delete[]的内容和delete相同void operator delete[] (void *ptr) throw(){ if(ptr) free(ptr);}
头文件<new>的源代码
namespace std { class bad_alloc : public exception { public: bad_alloc() throw() { } virtual ~bad_alloc() throw(); virtual const char* what() const throw(); }; struct nothrow_t { }; extern const nothrow_t nothrow; /// If you write your own error handler, it must be of this type. typedef void (*new_handler)(); /// Takes a replacement handler as the argument, returns the /// previous handler. new_handler set_new_handler(new_handler) throw();} // namespace stdvoid* operator new(std::size_t) throw(std::bad_alloc);void* operator new[](std::size_t) throw(std::bad_alloc);void operator delete(void*) throw();void operator delete[](void*) throw();void* operator new(std::size_t, const std::nothrow_t&) throw();void* operator new[](std::size_t, const std::nothrow_t&) throw();void operator delete(void*, const std::nothrow_t&) throw();void operator delete[](void*, const std::nothrow_t&) throw();// Default placement versions of operator new.inline void* operator new(std::size_t, void* __p) throw(){ return __p; }inline void* operator new[](std::size_t, void* __p) throw(){ return __p; }// Default placement versions of operator delete.inline void operator delete (void*, void*) throw() { }inline void operator delete[](void*, void*) throw() { }
扩展阅读
c++的new和delete
http://blog.csdn.net/liuyuan185442111/article/details/43027867
C与C++中的异常处理(new/delete)
http://blog.csdn.net/guoxiaoqian8028/article/details/8211775- C++:new和delete
- new和delete【C++】
- 【C++】char二维的new和delete
- C++new和delete的使用
- C++:new和delete的用法
- 【C++】new和delete隐藏的秘密!!!
- C ++的new、delete
- C++new和delete重载
- [C++]定制new和delete
- C++-关键字new和delete
- [C/C++] malloc/free和new/delete的区别
- C/C++中new/new[]和delete/delete[]的用法比较
- 【C++】new delete & new[] delete[]
- c/c++中malloc/free和new/delete的区别
- c++:动态内存分配(new和delete的使用)
- C++中new和delete的使用.c
- New和delete的原理
- New和delete的原理
- mysql简明语句
- c++ 冒泡排序改进
- 79-图片裁剪(自定义区域大小)
- 防止头文件重复包含
- 为来的路该如何走!
- c++的new和delete
- 79-图片擦除(纯代码)
- uva 11300 Spreading the Wealth (中位数的应用)
- java static block
- 如何在django中使用多个数据库
- Android Studio教程一----下载与安装
- 笔记本无线连接时(无本地连接) 与本地虚拟机相互ping通
- kafka consumer group总结
- dmesg-定位I/O问题