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
0 0
原创粉丝点击