c++中new和delete的用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++中new和delete的用法相关的知识,希望对你有一定的参考价值。

在C++编程中,使用new分配的数组可用delete释放。这里释放的是动态分配的数组空间,而不是静态分配的数组空间,详细步骤:

1、例如,我们动态创建了一个一维int数组arr,现在需要将它释放。

2、这时只需要使用delete[]数组名即可。

3、注意,要释放数组所占的内存,[]不能少。否则,用delete则不能完全释放数组所占内存空间。

4、例如,我们为一个二维数组arr动态分配了内存空间。现在需要将它释放。

5、这时候,单单使用一句delete[]arr是不够的。

6、而是应该先释放为二维数组的每行分配的空间(即delete[]arr[i]),再释放为行指针分配的空间(即delete[]arr)。

7、经过这样两步,动态分配的二维数组空间才算彻底地释放。至于多维数组的释放,其本质和二维数组是相似的,可以参考二维数组的方法。下图为编译运行截图。可以看到,顺利执行,没有非法的内存访问,也没有报错。

参考技术A new/delete究竟做了些什么?
在理解这个问题之前,我们先看一下下面的这段程序,有这么一个程序段:
class A

public:
A() cout<<"A is here!"<<endl;
~A() cout<<"A is dead!"<<endl;
private:
int i;
;
A* pA=new A;
delete pA;
在这个简单的程序段里面,new/delete究竟做了些什么?
实际上,这段程序里面隐含调用了一些我们没有看到的东西,那就是:
static void* operator new(size_t sz);
static void operator delete(void* p);
值得注意的是,这两个函数都是static的,所以如果我们重载了这2个函数(我们要么不重载,要重载就要2个一起行动),也应该声明为static的,如果我们没有声明,系统也会为我们自动加上。另外,这是两个内存分配原语,要么成功,要么没有分配任何内存。
size_t是什么东西呢?我在第一次看到这个动动的时候也是十分的困惑,毕竟以前没有见过。size_t在<cstddef>中定义,是一种无符号整数类型(不一定是int),用来保存对象的大小,这一用法是从C语言中借用过来的,现在你应该明白了吧(我学习的时候可是郁闷了好几天,没有人可以问,因为不知道有个csdn:)
new A;实际上做了2件事:调用opeator new,在自由存储区分配一个sizeof(A)大小的内存空间;然后调用构造函数A(),在这块内存空间上类砖砌瓦,建造起我们的对象。同样对于delete,则做了相反的两件事:调用析构函数~A(),销毁对象,调用operator delete,释放内存。不过需要注意的是,new分配一块内存的时候,并没有对这块内存空间做清零等任何动作,只是拿了过来,这块内存上放的仍然是原来的数据(垃圾数据),delete的时候,也只是释放这块内存,归还给操作系统,上面的数据还在上面,所以delete pA之后,pA的值没变,他指向的那块内存的值也没有变,不过似乎有什么问题,我们看一下下面的这个程序段:
int *p=new int(50000);
cout<<*p<<" "<<p<<endl;
delete p;
cout<<*p<<" "<<p<<endl;
我们可以清楚地看到,指针p存放的数据仍然是原来的地址,但是*p的内容却发生了变化,在我的机器上(win2000, VC6)始终是-572662307,不清楚这是为什么,难道系统做了什么手脚?还望高手指教。
在这里我们可以看到,new的工作实际上就是保证相互分离的存储分配和初始化工作能够很好的在一起工作,不过这里可能让初学者迷惑的是,我们定义了一个带有参数的new,但是我们用的时候却没有显式的去调用,而是让系统“神秘”的去提供这个参数。是的,这样做毫无疑问增加了复杂性,但是让基类获取了为一集派生类提供分配和释放服务的能力。

new/delete有什么好处和坏处?
从C程序员转换过来的C++程序员总是有个困惑:new/delete到底究竟和C语言里面的malloc/free比起来有什么优势?或者是一样的?
其实,就算我不说,你也应该很清楚了,new/delete当然比malloc/free要好,要不然,为什么还引进这个东东呢?其实通过上面的分析,我们看到了new/delete实际上做了很多malloc/free没有做的事情:malloc/free只是对内存进行分配和释放;new/delete还负责完成了创建和销毁对象的任务。
另外,new的安全性要高一些,因为他返回的就是一个所创建的对象的指针,对于malloc来说返回的则是void*,还要进行强制类型转换,显然这是一个危险的漏洞。
最后,我们可以对new/delete重载,使内存分配按照我们的意愿进行,这样更具有灵活性,malloc则不行。
不过,new/delete也并不是十分完美,大概最大的缺点就是效率低(针对的是缺省的分配器),原因不只是因为在自由存储区上分配(和栈上对比),具体的原因目前不是很清楚,不过在MCD上说了2个可能的原因:
1、new只是对于堆分配器(malloc/realloc/free)的一个浅层包装,没有针对小型的内存分配做优化。
2、缺省分配器具有通用性,它管理的是一块内存池,这样的管理往往需要消耗一些额外空间。

各种各样的new
一般来说,new有很多种形式,不过真的归纳起来,也就是2种:
1、最常用的形式:
void *operator new(std::size_t sz) throw(std::bad_alloc); (普通的)
void *operator new[](std::size_t sz) throw(std::bad_alloc); (数组的)
void *operator new(std::size_t sz);
void *operator new[](std::size_t sz)
这一种大家用得最为频繁,我就不举例子了。
2、放置new形式:
void *operator new(std::size_t count, void *ptr) throw(); (普通的)
void *operator new[](std::size_t count, void *ptr) throw(); (数组的)
要使用这种方式,必须包含头文件<new>。这个机制引入的初始目的是为了解决2个相关的问题:
1、把一个对象放在某个特定位置;
2、在某个特定分配区里面分配对象;
但是引入之后,发现这种机制远超出了简单的存储分配机制,我们可以给特定的存储位置关联任意的逻辑性值,这样一来,new就有了一种通用资源管理器的作用。同时第二个参数,也被扩展成了任意的可以识别的类型,并且配备了相应的nothrow版本:
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();

new能够返回NULL么?
我们经常看到有很多初学者喜欢写如下代码:
A* p=new A();
if(p==NUL) ....
写下这段代码的可能是受到了一些书上错误的影响,因为new A()从来就不可能返回NULL,如果在这个过程中用完了内存,那么他就会抛出bad_alloc异常,绝对不会返回NULL,如果你想让他返回null,应该用new(nothrow) A(),而不是new A()。不过从异常的观点来看,这实际上是一种倒退,我们应该尽量回避。
希望可以帮到你!!!本回答被提问者采纳
参考技术B new分配内存,delete释放内存,就这么简单。。。囧。。。
举个简单的例子
int * p = new int;
delete p;
使用完p后,要把内存释放了
参考技术C   对于计算机程序设计而言,变量和对象在内存中的分配都是编译器在编译程序时安排好的,这带来了极大的不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象。对于不能确定需要占用多少内存的情况,动态内存分配解决了这个问题。
  new和delete运算符是用于动态分配和撤销内存的运算符。
  一、new用法
  1.开辟单变量地址空间
  使用new运算符时必须已知数据类型,new运算符会向系统堆区申请足够的存储空间,如果申请成功,就返回该内存块的首地址,如果申请不成功,则返回零值。
  new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有标识符名。
  一般使用格式:
格式1:指针变量名=new 类型标识符;
格式2:指针变量名=new 类型标识符(初始值);
格式3:指针变量名=new 类型标识符 [内存单元个数];
  说明:格式1和格式2都是申请分配某一数据类型所占字节数的内存空间;但是格式2在内存分配成功后,同时将一初值存放到该内存单元中;而格式3可同时分配若干个内存单元,相当于形成一个动态数组。例如:
  1)new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址。int *a = new int 即为将一个int类型的地址赋值给整型指针a
  2)int *a = new int(5) 作用同上,但是同时将整数空间赋值为5
  2.开辟数组空间
  对于数组进行动态分配的格式为:
  指针变量名=new 类型名[下标表达式];
delete [ ] 指向该数组的指针变量名;
  两式中的方括号是非常重要的,两者必须配对使用,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。
  delete []的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。
  请注意“下标表达式”不必是常量表达式,即它的值不必在编译时确定,可以在运行时确定。
  一维: int *a = new int[100]; //开辟一个大小为100的整型数组空间
  二维: int **a = new int[5][6]
  三维及其以上:依此类推.
  一般用法: new 类型 (初值)
  二、delete用法
  1. 删除单变量地址空间
  int *a = new int;
  delete a; //释放单个int的空间
  2. 删除数组空间
  int *a = new int[5];
  delete []a; //释放int数组空间
  三、使用注意事项
  1. new 和delete都是内建的操作符,语言本身所固定了,无法重新定制,想要定制new和delete的行为,徒劳无功的行为。
  2. 动态分配失败,则返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
  3. 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身(指针p本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针。
  4. 内存泄漏(memory leak)和重复释放。new与delete 是配对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
  5. 动态分配的变量或对象的生命期。我们也称堆空间为自由空间(free store),但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放,往往会出错。
  6. 要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问。
  用new和delete可以动态开辟和撤销地址空间。在编程序时,若用完一个变量(一般是暂时存储的数据),下次需要再用,但却又想省去重新初始化的功夫,可以在每次开始使用时开辟一个空间,在用完后撤销它。

new和delete

sizeof不是函数,和它类似,new和delete也不是函数,它们都是C++定义的关键字,通过特定的语法可以组成表达式。

和malloc不同,malloc申请完空间后不会对内存进行必要的初始化,而new可以。

new的用法:

1、new()分配这种类型的一个大小的内存空间,并以括号中的值来初始化这个变量;

2、new[]分配这种类型的n个大小的内存空间,并以默认构造函数来初始化这些变量。

开辟单变量地址空间:

1、new int;  //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址。int *a=new int;

2、int *p=new int(5);  //作用同上,但是同时将整数赋值为5。

delete用法:

1、int *a=new int;

  delete a;  //释放单个int空间

2、int *a=new int[5];

  delete [] a;  //释放int数组空间

以上是关于c++中new和delete的用法的主要内容,如果未能解决你的问题,请参考以下文章

C++中Delete用法:请问int *p=new int(5); 此时delete的形式是delete []p还是delete p;

第四篇:new和delete的基本用法

C++中new的用法

C++中new和deletede 用法

C++初阶第七篇——C/C++的内存管理(C/C++动态内存分布+new和delete的用法和实现原理)

new和delete运算符 c/c++