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

问题聚焦:

我们都知道,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;

时间: 2024-12-21 05:55:18

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

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

(一) 先看下面的代码: string* stringArray = new std::string[100]; ... delete stringArray; 这样的做法是错误的,因为stringArray所含的100个string对象中的99个可能并没有被适当地删除,因为它们的析构函数很可能没有被调用. (二) 使用new时发生的事情: (1)内存被分配出来: (2)针对此内存会有一个或更多个构造函数被调用: 使用delete,也有两个动作: (1)针对此内存会有一个或更多个析构函数被调用:

[016]成对使用New和Delete时要采用相同形式

这一节比较简单,可以总结为以下: std::string *stringPtr1 = new std::string; std::string *stringPtr2 = new std::string[100]; .. delete stringPtr1; // delete an object delete [] stringPtr2; // delete an array of objects ◆总结 如果你在new表达式中使用[],那么释放内存的时候也一定要用delete [].如果未使

条款八: 写operator new和operator delete时要遵循常规

自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致.实际做起来也就是:要有正确的返回值:可用内存不够时要调用出错处理函数(见条款7):处理好0字节内存请求的情况.此外,还要避免不小心隐藏了标准形式的new,不过这是条款9的话题. 有关返回值的部分很简单.如果内存分配请求成功,就返回指向内存的指针:如果失败,则遵循条款7的规定抛出一个std::bad_alloc类型的异常.operator new实际上会不

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

string *stringarray = new string[100]; ... delete stringarray; 上述程序的运行情况将是不可预测的.至少,stringarray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用. 用new的时候会发生两件事.首先,内存被分配(通过operator new 函数,详见条款7-10和条款m8),然后,为被分配的内存调用一个或多个构造函数.用delete的时候,也有两件事发生:首先,为将被释放的内存调

EC笔记:第三部分:16成对使用new和delete

我们都知道,申请的资源,使用完毕后要释放.但是这个释放动作,一定要注意. 举个例子,很多人动态分配的资源,在使用之后,往往直接调用了delete,而不管申请资源的时候用的是new还是new[]. 如下: #include <iostream> using namespace std; int main(){ int *p; p=new int[256]; //某些操作 delete p; //错误,和分配资源时的操作不匹配 } 但是有时候,我们感觉写的代码是没有问题的,然而却犯了一些很隐晦的错

没有躲过的坑--成对使用new和delete时要采取相同的形式

new创建类对象与不new区别: new创建类对象需要指针接收,一处初始化,多处使用 new创建类对象使用完需delete销毁 new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间 new对象指针用途广泛,比如作为函数返回值.函数参数等 而且每个学习C++编程的人都知道成对的使用new和delete,也也就是new申请的内存用delete释放,new []申请的内存由delete []释放. std::string* first_string = new std::string;

effctive C++ 读书笔记 条款 16

条款16 成对使用new和delete时要采取相同形式 #include <iostream> #include <string> using namespace std; /* 条款16:成对使用new 和 delete时要采取相同形式 如果你在new表达式中使用[],必须在相应的delete表达式中也使用[],如果在new当中没有使用[],那么delete中也 不能使用[],两者是成对出现的. */ int main() { //第一版 : 报错 /* string * p_s

EC读书笔记系列之9:条款16、17

条款16 成对使用new和delete时要采取相同形式 记住: ★若你在new表达式中使用[ ],必须在相应的delete中也使用[ ],反之亦然 ------------------------------------------------------------------ 当结合typedef使用时,应特别注意:如: typedef std::string AddressLines[4]; std::string *pal = new AddressLines; //等同于new str

Effective C++ 条款16

成对使用new和delete时要采取相同形式 本节条款知识点在于delete和delete[]的区别 大家都知道在new一个对象的时候要delete一个对象,在new 一个对象数组时要delete[]才是正确的. 大家也知道new产生两个行为,一个是申请对象所需内存,另一个是调用类构造函数初始化对象. 那么,delete的行为也有两个,一个是调用对象的析构函数,另一个是回收内存. 而new[]是对每个对象都进行上面同样的行为. 这时候如果不小心new匹配了delete[],或者new[]匹配了d