读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式
1. 一个错误释放内存的例子
下面的场景会有什么错?
std::string *stringArray = new std::string[]; ... delete stringArray
一切看上去都是有序的。new匹配了一个delete。但有一些地方确实是错了。程序的行为是未定义的。至少来说,stringArray指向的100个string对象中的99个看上去都不能被正确释放,因为他们的析构函数可能永远不会被调用。
2. 使用new 和delete时究竟做了啥?
当你使用一个new表达式(通过使用new动态的创建一个对象)时,会发生两件事情。第一,内存被分配(通过一个叫做operator new的函数,看Item 49和Item 51)。第二,在分配的内存上调用了一个或多个构造函数。当你使用一个delete表达式时,另外两件事情会发生:在内存上调用了一个或者多个析构函数,然后内存被解除分配(通过调用叫做operator delete的函数,见 Item 51)。关于delete的一个重要的问题是:在即将被删除的内存中究竟有多少对象?这个问题的答案决定了有多少个析构函数必须被调用。
3. new和delete不配对使用为啥会出错?
实际上,下面这个问题更加简单:被删除的指针是指向一个单独的对象还是指向数组的所有对象?这是个关键的问题,因为单个对象的内存分配通常情况下同数组的内存分配是不一样的。特别的,一个数组的内存通常包含了数组的大小,因此delete很容易就会知道需要调用多少个析构函数。单个对象的内存却没有这样的信息。你可以将内存不同分配想象成下面这个样子,n是数组的大小:

当然这只是一个例子。编译器不需要这么实现,虽然很多编译器确实是这么实现的。
当你在一个指针上使用delete时,delete能够知道数组容量信息是否存在的唯一方法就是通过你来告诉它。如果当你使用delete时用了“[]”,delete认为指针指向一个数组。否则,它会认为它在指向一个单一的对象:
std::string *stringPtr1 = new std::string; std::string *stringPtr2 = new std::string[]; ... delete stringPtr1; // delete an object delete [] stringPtr2; // delete an array of objects
4. new和delete不配对使用会有什么后果?
如果你在stringPtr1上使用“[]”将会发生什么?结果是未定义的,但是结果不会太好。假设内存分布如上图所示,delete会读取一些内存并把它所读到的解释为一个数组容量,接下来就开始多次调用析构函数,却忽略的以下事实:它处理的内存不但不是一个数组,也可能并没有包含它正忙着释放的那种类型的对象。
如果你不在stringPtr2上使用“[]”会发生什么?结果也是未定义的,但是你可以看到这会导致过少的构造函数被调用。此外,对于像int的内建类型来说结果也是未定义的(有时甚至是有害的),虽然内建类型没有析构函数。
规则很简单:如果你在一个new表达式中使用”[]”,你必须在对应的delete表达式中使用”[]”,反之亦然。
当你实现一个包含指向动态分配内存的指针的类,并且同时提供多个构造函数的时候,你需要将上面的重要规则记在心中,因为你必须当心在对构造函数中对指针成员进行初始化时,new必须使用相同的形式。如果你不这么做,你又怎么能知道在析构函数中将使用什么形式的delete呢?
5. 使用typedef时需要注意new和delete的配对使用
对于倾向于使用typedef的人来说这条规则同样值得注意,因为这意味着typedef的作者必须指出使用new来创建typedef类型的对象时,使用什么形式的delete对其进行销毁。看下面的例子:
typedef std::string AddressLines[]; // a person’s address has 4 lines, // each of which is a string
因为AddressLines是一个数组,new应该这么使用:
std::string *pal = new AddressLines; // note that “new AddressLines” // returns a string*, just like // “new string[4]” would
使用delete的形式必须和new相匹配:
delete pal; // undefined! delete [] pal; // fine
为了避免这种混淆,不如放弃在数组类型上使用typedef。这很容易,因为标准c++库(见Item 54)中包含string,vector和模板,使得对动态分配数组的需求几乎将为0。这里我们举个例子,AddressLines可以被定义成由strings组成的vector,也就是类型 vector<string>。
读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式的更多相关文章
- Effective C++(16) 成对使用new和delete时要采取相同的形式
问题聚焦: 我们都知道,new和delete要成对使用,但是有时候,事情往往不是按我们预期的那样发展. 对于单一对象和对象数组,我们要分开考虑 遇到typedef时,也需要 ...
- 读书笔记 effective c++ Item 50 了解何时替换new和delete 是有意义的
1. 自定义new和delete的三个常见原因 我们先回顾一下基本原理.为什么人们一开始就想去替换编译器提供的operator new和operator delete版本?有三个最常见的原因: 为了检 ...
- 读书笔记 effective c++ Item 31 把文件之间的编译依赖降到最低
1. 牵一发而动全身 现在开始进入你的C++程序,你对你的类实现做了一个很小的改动.注意,不是接口,只是实现:一个私有的stuff.然后你需要rebuild你的程序,计算着这个build应该几秒钟就足 ...
- 读书笔记 effective c++ Item 18 使接口容易被正确使用,不容易被误用
1. 什么样的接口才是好的接口 C++中充斥着接口:函数接口,类接口,模板接口.每个接口都是客户同你的代码进行交互的一种方法.假设你正在面对的是一些“讲道理”的人员,这些客户尝试把工作做好,他们希望能 ...
- 读书笔记 effective c++ Item 30 理解内联的里里外外 (大师入场啦)
最近北京房价蹭蹭猛涨,买了房子的人心花怒放,没买的人心惊肉跳,咬牙切齿,楼主作为北漂无房一族,着实又亚历山大了一把,这些天晚上睡觉总是很难入睡,即使入睡,也是浮梦连篇,即使亚历山大,对C++的热情和追 ...
- 读书笔记 effective c++ Item 51 实现new和delete的时候要遵守约定
Item 50中解释了在什么情况下你可能想实现自己版本的operator new和operator delete,但是没有解释当你实现的时候需要遵守的约定.遵守这些规则并不是很困难,但是它们其中有一些 ...
- 读书笔记 effective c++ Item 54 让你自己熟悉包括TR1在内的标准库
1. C++0x的历史渊源 C++标准——也就是定义语言的文档和程序库——在1998被批准.在2003年,一个小的“修复bug”版本被发布.然而标准委员会仍然在继续他们的工作,一个“2.0版本”的C+ ...
- 读书笔记 effective c++ Item 52 如果你实现了placement new,你也要实现placement delete
1. 调用普通版本的operator new抛出异常会发生什么? Placement new和placement delete不是C++动物园中最常遇到的猛兽,所以你不用担心你对它们不熟悉.当你像下面 ...
- 条款16:成对使用new和delete时,采取相同的形式
问题聚焦: 我们都知道,new和delete要成对使用,但是有时候,事情往往不是按我们预期的那样发展. 对于单一对象和对象数组,我们要分开考虑. 遇到typedef时,也需要搞 ...
随机推荐
- jQuery EasyUI学习资源汇总
jQuery EasyUI学习资源汇总 EasyUi – 1.入门 EasyUi – 2.布局Layout + 3.登录界面 EasyUi – 4.datwagrid 学习Jquery EasyUI的 ...
- CentOS标准目录结构
原博:http://www.centoscn.com/CentOS/2014/0424/2861.html/ 最高层root --- 启动Linux时使用的一些核心文件.如操作系统内核.引导程序Gru ...
- iOS 之 系统机制
iOS 沙盒 iOS 8 之 新特性 iOS 操作系统整体架构层次讲解
- JAVA短信验证登录
短信验证登陆 1.点击触发,以电话号码为参数调用发送验证登录短信方法 2.默认模板为验证模板 生成6位验证码 3.将生成的验证码和手机号码放入缓存,(已经设置好缓存存放时间) 4.调用发送模板短信方法 ...
- css3实战版的点击列表项产生水波纹动画
1.html+js: <!DOCTYPE html><html><head lang="en"> <meta charset=&qu ...
- Zepto 使用中的一些注意点(转)
http://www.zeptojs.cn/ zepto英文站在线文档 http://www.css88.com/doc/zeptojs_api/ zepto中文站在线文档 htt ...
- Sublime Text3 常用快捷键动画演示及优秀插件分享
Sublime Text 是前端的一个神器,以其精简和可DIY而让广大fans疯狂.好吧不吹了直入正题 -_-!! 首先是安装,如果你有什么软件管家的话搜一下就好,一键安装.然后,有钱的土豪就自己买个 ...
- 判断移动端设备: navigator.userAgent.toLowerCase()
判断你的浏览设备: navigator.userAgent.toLowerCase(); (返回当前用户所使用的是什么浏览器,将获得的信息变成小写) function browserRedirect( ...
- angular指令中,require和transclude同时设置为true时的作用
最近在学习angularJS指令的时候,对指令对象中require属性和transclude属性同时设置为true比较疑惑,于是自己动手测试一下具体差异 index.html: <simple& ...
- --@angularJS--指令与控制器之间的交互demo
1.index.html: <!DOCTYPE HTML><html ng-app="app"><head> <title>c ...