问题聚焦:
    我们都知道,new和delete要成对使用,但是有时候,事情往往不是按我们预期的那样发展。
    对于单一对象和对象数组,我们要分开考虑。
    遇到typedef时,也需要搞清楚,是单一对象类型还是对象数组类型。

来看一个例子:
std::string* stringArray = new std::string[100];
...
delete stringArray;

  问题:stringArray所含的100个string对象中的99个可能并没有被适当地删除,因为它们的析构函数很可能没有被调用。


我们来了解一下,使用new时发生了什么,一共有两个动作:
  1. 内存被分配出来
  2. 针对此内存会有一个或更多个构造函数被调用
使用delete,也有两个动作:
  1. 针对此内存会有一个或更多个析构函数被调用
  2. 内存被释放
这个问题的关键:
delete的最大问题在于,即将被删除的内存之内究竟有多少个对象?这个问题的答案决定了有多少个析构函数必须被调用。
简单地说就是:
即将被删除的那个指针,所指的是单一对象,还是对象数组。因为单一对象的内存布局和对象数组的内存布局是不一样的。更明确的说,数组所用的内存通常还包括“数组大小”的记录,以便delete知道需要调用多少次析构函数。单一对象的内存则没有这笔记录。
你可以把两种不同的内存布局想象如下的形式,其中n是数组的大小:

当你对着一个指针使用delete,唯一能够让delete知道内存中是否存在一个“数组大小记录”的方法就是:有你来告诉它。如果你使用delete时加上中括号,delete便认定指针指向一个数组,否则它便认定指针指向单一对象。
像下面的代码:
std::string* stringPtr1 = new std::string;
std::string* stringPtr2 = new std::string[100];
...
delete stringPtr1;
delete[] stringPtr2;

  如果对stringPtr1使用delete[]形式,delete会读取若干内存并将它解释为“数组大小”,然后开始多次调用析构函数。这是很危险的,同时编译器是不会帮你检查的。

如果对stringPtr2使用delete形式,这会导致较少的析构函数被调用,这种错误对于内置类型int也是不可以的,虽然这种类型没有析构函数。


所以游戏规则很简单:

如果你调用new时,使用new[] 的形式,那么对应调用delete时也使用[],
如果你调用delete时,没有使用new[] 的形式,那么对应调用delete时也不应该使用[] 形式。

当使用typedef时,要变得尤为敏感,因为你必须要明确地知道,这时的new是一个什么样的形式:
typedef std::string AddressLines[4];       // 每个人的地址有4行,每行是一个string,typedef用于掩饰复合类型

// 这时候AddresLines是一个数组,所以new时,应该是[]形式
std:string* pal = new AddresLines; // 相当于:new string[4];
//那么,必须匹配数组形式的delete
delete pal; // error,行为未定义
delete[] pal; // pass

  所以,最好尽量不要对数组形式使用typedef动作。


 最后在看360的一道在线笔试题目:
假定指针变量p定义为“int *p=new int(100);”,要释放p所指向的动态内存,应使用语句delete p还是delete[] p。

  这个问题很简单,注意int后面是小括号,所以:

1.new int[] 是创建一个int型数组,数组大小是在[]中指定,例如:
int * p = new int[10]; //p执行一个长度为10的int数组。 2. new int()是创建一个int型数,并且用()括号中的数据进行初始化,例如:
int *p = new int(10); // p指向一个值为10的int数。

  所以正确的形式是delete p;


有关这个知识点再来看一道面试题:
使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?

不会有内存泄露,但不建议用

  当用delete来释放用new int[]申请的内存空间时,由于其为基本数据类型没有析构函数,所以使用delete与delete []相同,两者都会释放申请的内存空间,若是自定义的数据类型,有析构函数时,用new []申请的空间,必须要用delete []来释放,因为要delete []时会逐一调用对象数组的析构函数,然后释放空间。总而言之就是delete某一个指针都能够回收申请的内存空间,但是对于自定义的数据类型,要分别调用每一个对象的析构函数,所以在收回内存空间之前要先挨个的调用析构函数。delete[]的作用就是,先根据前面的n确定有几个对象,然后确定每个对象的边界,依次调用它们的析构函数。

条款16:成对使用new和delete时,采取相同的形式的更多相关文章

  1. Effective C++(16) 成对使用new和delete时要采取相同的形式

      问题聚焦:     我们都知道,new和delete要成对使用,但是有时候,事情往往不是按我们预期的那样发展.     对于单一对象和对象数组,我们要分开考虑     遇到typedef时,也需要 ...

  2. 读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式

    1. 一个错误释放内存的例子 下面的场景会有什么错? std::]; ... delete stringArray 一切看上去都是有序的.new匹配了一个delete.但有一些地方确实是错了.程序的行 ...

  3. Effective C++ -----条款16:成对使用new和delete时要采取相同形式

    如果你在new表达式中使用[],必须在相应的delete表达式中也使用[].如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[].

  4. 条款16:成对使用new和delete时要采取相同形式

    NOTE: 1.如果你在new表达式中使用[],必须在相应的delete表达式中也使用[].如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[].

  5. 【16】成对使用new和delete时要采取相同形式

    简而言之,new时不带[],delete时也不带[]:new时带[],delete时也要带[].如果不匹配,要么造成多销毁对象,导致未定义行为:要么导致少销毁对象,导致内存泄漏.

  6. [Effective C++ --016]成对使用New和Delete时要采用相同形式

    这一节比较简单,可以总结为以下: std::string *stringPtr1 = new std::string; std::]; .. delete stringPtr1; // delete ...

  7. 条款16:成对使用new和delete时要使用相同的形式

    请牢记: 如果在new表达式中使用[],必须在相应的delete表达式中也使用[]. new[]  对应  delete[] 如歌在new表达式中不适用[],一定不要在相应的delete表达式中使用[ ...

  8. 条款五:对应的new和delete要采用相同的形式

    string *stringarray = new string[100]; ... delete stringarray; 上述程序的运行情况将是不可预测的.至少,stringarray指向的100 ...

  9. 条款16:成对使用 new和delete时要采取相同的形式

    std::string* stringPtr1=new std::string; srd::string* stringPtr2=new std::string[100];   对应地 delete也 ...

随机推荐

  1. Introduction the naive“scull” 《linux设备驱动》 学习笔记

    Introduction the naive "scull" 首先.什么是scull? scull (Simple Character Utility for Loading Lo ...

  2. 一键搞定Java桌面应用安装部署 —— exe4j + Inno Setup 带着JRE, 8M起飞

    转载自:http://www.blogjava.net/huliqing/archive/2008/04/18/193907.html 对于作Java桌面应用来说,比较烦人的就是安装部署问题,客户端是 ...

  3. iOS实践01

    去年放假之前大概完成了新浪微博项目,到现在也忘得差不多了,打算在重新写一遍.之前的一些笔记在新浪的博客SleenXiu,在这主要是把新浪微博以随笔的形式写在这,方便以后的复习. 先看看之前主要完成的几 ...

  4. BZOJ 1974: [Sdoi2010]auction 代码拍卖会( dp )

    在1, 11, 111……中选<=8个, + 11..(n个1)拼出所有可能...这些数mod p至多有p中可能, 找出循环的处理一下. 那么dp就很显然了...dp(i, j, k)表示前i种 ...

  5. Java学习之字符串练习

    1.给定一个字符串数组.按照字典顺序进行从小到大的排序. * 思路: * 1,对数组排序.可以用选择,冒泡都行. * 2,for嵌套和比较以及换位. * 3,问题:以前排的是整数,比较用的比较运算符, ...

  6. Collections之sort的两个方法(自然排序和自定义比较器排序)

    Collections是个服务于Collection的工具类(静态的),它里面定义了一些集合可以用到的方法. 本文演示了Collections类里sort()的两个方法.第一种只需传入被排序的集合,便 ...

  7. 启动tomcat的时候,服务器暂停到装载mysql驱动文件的原因

    1.使用spring+mybatis,由于mybatis的配置文件中jdbc类型的错误使得,tomcat无法正常启动,在编写mybatis一定确保jdbc类型,java类型正确,jdbc类型要大写! ...

  8. Notepad++使用技法

    Alt+H 隐藏行 Ctrl+Tab  实现在多个打开的窗口间切换 Ctrl+Shift+Q区块注释 Ctrl+K行注释(取消Ctrl+Shift+K) 文件  新建文件 Ctrl+N  打开文件 C ...

  9. python2.7_1.14_编写一个简单的回显客户端/服务器应用

    1.服务端 server.py # -*- coding: utf-8 -*- import socket import argparse host = 'localhost' data_payloa ...

  10. No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s)

    In Build Settings are: Architectures: Starndard (armv7, armv7s) Base SDK: Latest iOS (iOS 6.0) Build ...