new和delete与内存分配

原创 2016年08月29日 20:17:12

一、Effective C++条款16:成对使用new和delete时采用相同的形式

通常我们使用new和delete有两种情形,第一,动态的为单一对象分配内存,第二,动态的创建数组。new和delete的使用需遵循许多规则,这里着重理解相同形式这一关键词。且看下面的动作有什么错?

std::string *stringArray = new std::string[100];

...
delete stringArray;
乍看起来,同时使用了new和delete,似乎没什么错误。这里使用new在运行阶段动态分配了100string对象,但是仅使用delete只释放掉了单一对象的所占用的内存,其中99个string对象不太可能被适当的删除,因为它们的析构函数没有被调用。

请注意:这里仅仅同时使用了new和delete,但并没有满足相同的形式这一条件。我们所面临的问题可以更简单的叙述为:即将被删除的那个指针,所指的是单一对象还是对象数组?另外,请尽量使用C++11智能指针,以防止写代码时忘记释放掉new分配的内存而导致内存泄漏。

请记住

如果在new表达式中使用了[],必须在相应的delete表达式中使用[]。如果在new表达式中不使用[],一定不要在相应的delete表达式中使用[]。确保“同时使用、相同形式”。

二、使用new动态分配内存

为单一对象(可以是数据结构,基本类型或类)获得并指定分配内存的通用格式如下:

typeName *pointter_name  = new typeName;

例如,在运行阶段为一个int值分配未命名的内存,并使用指针来访问这个值,可以写为:int * pn = new int;

程序员告诉new要为int类型的数据类型分配内存,new根据这种数据类型找到长度(在这里int为4个字节)正确的内存块,并返回内存块的地址,程序员负责将该地址赋给一个指针(pn是被声明为指向int的指针,现在pn是一个地址,而*pn为存储在那里的值)。


请看下面的例子:

int *pt = new int;

*pt = 1001;

double *pd = new double;

*pd = 3.14;


则有:如果这里int占4个字节,double占8个字节,则sizeof(pt)为4,sizeof(*pt)为4。sizeof(pd)为4,sizeof(*pd)为8。这里,指向int的指针的长度与指向double的指针相同,它们都是地址,但由于声明了指针的类型,因此程序知道*pd为8个字节的double值,*pt为4个字节的int值。

三、使用new和delete时要遵循的规则

  • 不要使用delete释放不是new分配的内存。
  • 不要使用delete释放同一个内存两次。
  • 使用new[]为数组分配的内存一定要使用delete[]释放,不能使用delete;new为单个对象分配的内存一定使用delete来释放。
  • 对空指针delete是安全的。

四、使用动态数组

创建动态数组后,如何使用数组中的元素?

int *pt = new int[10]; // get  a block of 10 ints

如果这里int占4个字节,上述语句中sizeof(pt)为4个字节,sizeof(*pt)为4 × 10个字节。那么如何使用数组中的元素呢?其实和普通数组一样。


double *pd = new double[3];

pd[0] = 1.0;

pd[1] = 2.0;

pd[2] = 3.0;


那么,pd[0](或*pd) 的值为1.0。如果有pd = pd + 1;, 那么pd[0]的值为2.0。另外请注意,不能修改数组名(常量),但指针(pd)为变量,因此可以修改它的值。而且pd+1的效果是指指针指向数组第一个元素的下一个位置,即第二个元素,因此pd[0]为2.0。

五、杂项

指针和数组等价的原因在于指针算术和C++内部处理数组的方式。首先我们来看一下算术,将整型变量加1后,其值将增加1;但将指针变量增加1后,增加的量等于它指向的数据类型的字节数,如:将指向double的指针加1后,如果系统对double使用8个字节存储,则其值增加8。另外,C++将数组名解释为数组第一个元素的地址。

double arrD[3] = {1.0, 2.0, 3.0};

short arrSh[3] = {1, 2, 3};

double *pd = arrD; // 等价于&arrD[0]

short *psh = &arrSh[0];

...

假设double占4个字节,short占2个字节,则:arrD[0] ,*arrD和*(arrD + 0)等价,其值为1;*psh为1。

sizeof(arrD)为3 × 8 = 24,sizeof(pd)为4,sizeof(*pd)为8。

sizeof(arrSh)为3 × 2 = 6,sizeof(psh)为4,sizeof(*psh)为2。

这是因为 指针为指向变量的地址,且地址占4个字节;对指针的解引用为指针指向变量的值,所占内存谓该值所属类型所占的字节数。



注意:虽然数组名被解释为指向数组第一个元素的地址,但不能修改数组名,是因为数组名为常量;可以修改指针,是因为指针(指向变量的地址)为变量。

pointerName = pointerName + 1; // valid

arrayName = arrayName + 1; // not alllowed


数组的地址

数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。

short tell[10];     // tell为20字节的数组

cout << tell ;    // &tell[0] 即数组第一个元素的地址,占2个字节的内存块的地址

cout << &tell;  //  整个数组的地址,从数字上说,该地址和tell的地址相同,但是&tell为占20个字节的内存块的地址


总之,使用new来创建数组以及使用指针来访问不同的元素时,只需要把指针当成数组名对待即可。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

C++的new、delete及其内存管理

代码写多了,就麻木了。new和delete很好用,平时用的时候没想太多。但如果“想太多”就会引发出很多东西。 new和delete跟sizeof一样,是操作符,关键字,而不是函数。new和dele...

C++学习:malloc/free和new/delete动态内存分配

C++学习:malloc/free和new/delete简介: 在C语言中,内存的申请和释放采用的是malloc/calloc/realloc/free来实现的,而在C++语言中,不仅可以使用以上的...

内存分配方式,堆区,栈区,new/delete/malloc/free

原博地址:内存分配方式,堆区,栈区,new/delete/malloc/free 1.内存分配方式 内存分配方式有三种: [1]从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存...

内存分配方式,堆区,栈区,new/delete/malloc/free

1.内存分配方式内存分配方式有三种:[1]从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。[2]在栈上创建。在执行函数时,函数...

C++ 方式的内存分配与释放 new 和 delete

C++ 方式的内存分配与释放 new 和 delete 在内存管理上,C++ 和 C 有着完全不同的两套方案。当然,C++的总是同时兼容C。C的那一套方案在C++里同样可行。 我们首先...

placement new和placement delete跟踪内存分配

源文件: NewDeleteDemo.cpp #include #include #include /***********************************...

C++ 笔记 关于动态内存分配 (new / delete)

C语言里面的动态内存分配用的是malloc()/calloc()和free()其中,malloc用于分配一个单位的内存,返回指针。例如malloc(sizeof int) calloc用于分配多个内...

C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free

内存分配方式 内存分配方式有三种: [1] 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量, static 变量。 [2] 在栈上创建。在执行函...

动态内存分配(new delete)

一、动态内存分配的引入 一般,变量和对象在内存中的分配都是编译器在编译程序时安排好了的,这带来了极大的不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象。动态内存分配解决了这个问题。 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)