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

127 篇文章 7 订阅
39 篇文章 3 订阅

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

Use the same form in corresponding uses of new and delete.

首先,对于以下代码:

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

虽然乍一看,这段代码并没有什么不妥,确实是成对使用了new和delete,但还是存在错误,因为程序中存在不明确的行为:

  • 在stringArray内所含的100个上图日国内对象中,有99不太可能被适当的删除,因为它们的析构函数很有可能没有被调用。

new与delete

当我们使用new关键字时——通过new动态生成一个对象,会发生两件事:

  • 内存被分配出来(通过operator new函数)
  • 针对此内存会有一个(或者更多)的构造函数被调用。

而当我们使用delete关键字时,也会发生两件事:

  • 针对次内存会有一个(或者更多)的析构函数被调用。
  • 内存被释放出来(通过operator delete函数)

但是,delete的最大问题在于:

  • 即将被删除的内存之中到底有多少个对象?这关系到有多少的析构函数应该被调用。

因此,对于这个问题,可以用更为简单的方式进行理解:即将被删除的指针,所指的到底是单一对象还是对象数组?之所以要分清,是因为一般而言,单一对象的内存布局不同于数组的内存布局。更明确的说 :

  • 数组所用的内存还包括“数组大小”的记录,以便delete直到需要调用多少次的析构函数。

虽然数组有这样的记录,但是当我们对着一个指针使用delete时,唯一能够让delete知道内存中存在一个“数组大小记录”的方法是:由我们去告诉它——

  • 如果在使用delete时加上中括号,delete就会认定指针指向一个数组,否则它就认定指针指向单一的对象。
std::string* stringPtr1 = new std::string;
std::string* stringPtr2 = new std::string[100];
...
delete stringPtr1;      //删除一个对象
delete [] stringPtr2;   //删除一个由数组组成的数组

对于上面两种的形式:
1,如果我们对stringPtr1使用delete []的形式,会产生不理想的未定义结果。此时,delete会读取若干的内存并将它们解释为“数组大小”,然后开始多次调用析构函数,殊不知这块内存并不是一个数组,其上也没有应该销毁的对象。

2,如果我们没有对stringPtr2使用delete []的形式,依然会产生不理想的未定义结果。因此此时,可能会导致太少的析构函数被调用。另外,对于没有析构函数的内置类型(如int型),这种操作也是未定义的、甚至有害。

总之:

  • 如果调用new时使用[],就必须在对应调用delete时也使用[]。
  • 如果调用new时没有使用[],那么也不应该在对应调用delete的位置使用[]。

当我们撰写的class含有一个指针指向动态分配的内存、并提供多个构造函数时,这个规则就非常重要,因为这种情况下必须很小心的在所有构造函数中使用相同形式的new将指针成员初始化。如果没有这样做,就没法在析构函数使用对应形式的delete。

在使用typedef时,这条规则也十分重要,因为在使用new的方式创建该种typedef类型对象时,应该以哪一种delete形式将其删除,必须要表达清楚:

typedef std::string AddressLines[4];    //表示每个人的地址有四行,每行是一个string

由于AddressLines是一个数组,如果这样使用new:

std::string* pal = new AddressLines;  //此时,“new AddressLines”返回一个string*
                                      //就像“new string[4]”一样

那么就必须匹配“数组形式”的delete:

delete pal;     //未定义的行为!错误!
delete [] pal;  //正确的行为

当然,为了避免这样的错误,尽量不要对数组形式做typedef操作。因为C++标准库中含有string,vector等templates,对于上面这个例子中,就可以将AddressLines定义为vector< string >就完事儿了。

最后:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值