您的位置:首页 > 编程语言 > C语言/C++

C++中 new/delete 概念和用法总结

2013-08-24 16:25 357 查看
学过C++的程序员都知道,new/delete是其管理内存的主要方法。与C语言相比,C++支持面向对象技术,因此在内存管理方面有所区别。

      在C++中,数据对象(基本类型和复合类型)的创建包括两个部分:一是给数据对象分配足够的内存,二是内存进行数据的初始化。而C中,只有第一个分配内存的作用。并且,不仅仅是类,其它基本类型,如int型等,也是如此。例如:

      char* pc1 = new char;

      char* pc2 = new char('A');

      以上两条语句都能够给对应的指针分配内存,不同在于,第一条语句仅仅分配内存,而具体的内容是随机的;而第二条语句不仅分配内存,并且赋值为‘A’。相对应的,当不再需要这些内存时候,可以采用delete来释放内存。

      C++中,关于new/delete相关的内容很多,初学者比较容易混淆概念。以下是笔者的一点总结,希望对那些还处于懵懵懂懂的程序员有帮助。

      1. new/delete 关键字。C++和其它语言一样,也事先预留了一些单词作为系统使用。程序员是不能用这些单词来表示自己的数据的。如int , float, struct , class 等。当然new/delete也是。但是new/delete关键字仅仅是在词法上的定义,它只表明程序员不能重复定义它们,用来表达其它含义。

      2. new/delete表达式。指的是new/delete与其它单词所组成的一条有具体词义的语句(运算符形式)。如 new char; 就是分配大小为一个byte的内存空间。在C++中,new/delete表达式在不同的情况下,有不同的实现途径。但是实现的功能都是一样的,就是处理内存相关操作。

      3. operator new 和 operator delete 函数。这点很奇怪,在C++中,某些运算符号可以重载为函数来使用(尽管运算本身就是一种抽象的对数据处理的函数方式),因此operator new 和 operator delete是两个函数名称。但是这两种函数只是,分配内存而不初始化。这点与C语言的malloc和free比较类似。

      4. 类成员函数new/delete。指的是类的成员函数,并且函数名是new和delete。这与3. 中的函数有点类似,只是3. 中的函数是标准空间中的函数,而类成员函数是类本身的成员函数。

      接下来,是这4条之间的关系。1. 只是说明 new/delete两个单词程序员不能再定义使用,与具体的功能毫无关系。2.是一条与实际条件相关的,具有内存分配功能的表达式。 3.4是函数名,只是作用的空间大小不一样。简单说来就是: 单词, 表达式, 函数名 和 函数名。

      当C++编译器碰到new/delete表达式的时候,它会去寻找相关的内存处理方式。 如果表达式的对象并没有定义自己的成员new函数,那么它就会去调用全局的new函数去分配内存;反之则调用成员函数的new函数去分配内存。接着根据参数的不同,去调用相应的初始化函数,也就是构造函数。也就是说new表达式会执行两个步骤:分配内存和初始化。 在分配内存的阶段,new表达式会有2种分配方式:全局的 operator new 或者是自定义的new成员函数。而初始化工作是调用构造函数来完成的。delete表达式功能和次序刚好相反,但是还是同意的机制。这就是new/delete相关几个概念的区别。一般地,不要去修改全局的operator
new/ operator delete函数,但是根据需要,可以定义类的相应的成员函数来改变内存分配的方式。

      关于new还单有一种功能(其实也是new的一种重载方式,但不进行分配内存操作,只是返回原来的内存地址),就是在指定的内存空间上创建一个对象,用法如下:

      char buff[20];

      CNone* pNone = new (buff) CNone();

      假设CNone的大小不超过20个字节,那么就在buff开头的内存上,初始化一个对象。接着就可以通过pNone来进行操作。释放的方法如下:

      pNone->~CNone();

      那么类pNone对象就会被释放,但是内存buff并没有释放,依旧存在。

      重载new/delete的原则是:尽量不要重载(很矛盾啊),除非完全清楚具体的分配情况。如果要重载,那么要实行配对法则。就是有new的重载,必须有其对应的delete重载,尽管有时候delete并不会进行内存的释放。

      常见的重载函数形式有(参考<new>):

      void*  operator new (size_t size) throw(std::bad_alloc);

      void    operator delete (void* addr) throw();

 

      void*  operator new[] (size_t size) throw(std::bad_alloc);

      void    operator delete[] (void* addr) throw();

 

      void*  operator new (size_t size,  nothrow_t &n) throw();

      void    operator delete (void* addr, nothrow_t &n) throw();

 

      void*  operator new (size_t size,  void* p) throw() { return p;}

      void    operator delete (void* addr, void* p) throw() { }

      除了最后一组外,其它组的内存分配就根据实际情况来实现。注意,对于size数值为0的情况,要在内部实现为1。这是因为C++标准要求空对象也要有实际的意义。

      但是重载模式并不限于以上几组,原则上重载的new/delete组对有无数对,但是和实际相关的就只有那么几组而已。要注意的是,所有new/delete成对出现,但并不是代表用带参数的new创建的对象,在销毁的时候同样使用相同参数的delete去销毁,实际上是用标准的delete和delete[]去销毁的。对应的delete是在相应的对象创建失败时候,才调用的;并且不能是分配内存的时候,只能是在构造函数中出现异常时候才可以。这是系统自动实现的。并且按照从作用域的小到大进行搜索,找到一个捕获这个异常处理之后结束,否则就可能造成内存泄漏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: