天天看点

《C++编程风格(修订版)》——2.6 动态内存的回收

本节书摘来自异步社区出版社《c++编程风格(修订版)》一书中的第2章,第2.6节,作者:【美】tom cargill,更多章节内容可以访问云栖社区“异步社区”公众号查看。

c++编程风格(修订版)

string 类在管理动态内存时还存在着第二个问题:“内存泄漏”,当所有使用 new 来分配的动 态内存并没有都使用 delete 来进行释放时,就会发生内存泄漏。string 类中的内存泄漏既不在构 造函数中,也不在析构函数中。我们可以看到,在每个构造函数中仅执行一次 new,以获得一个 指向字符数组的指针,并把这个指针保存在 s 中。在 string 对象中总是包含有一个数组来存储字 符串,并且这块内存在对象生存期结束时,将会通过在析构函数中调用 delete[] s 来进行释放。

在 concat() 中存在着内存泄漏,因为在函数中分配新的数组时,并没有释放对象中当前的数 组。当 concat() 执行下面的语句时:

《C++编程风格(修订版)》——2.6 动态内存的回收

s 马上被一个新的指针值覆盖,而前一个指针值则被抛弃了,这就使得前一个指针所指向字 符数组成为了一块垃圾内存。

为了改正这个内存泄漏问题,concat() 必须保证原有的数组一定要被删除。我们在每次使用 new 时都将创建一个动态对象(在本例中是一个动态数组),对于每个动态对象,很关键的一件事就是 建立一个“所有者”——当不再需要动态内存时,所有者应该负责销毁动态对象。最简单的所有者 策略就是,将执行 new 操作的对象作为动态对象的所有者,并且必须由所有者来负责删除动态对象。 根据这个策略,string 类就必须负责删除所有在构造函数或者其他的成员函数中分配的字符数组。

对于每个 new操作,都要有相应的 delete操作。

对于 concat() 中的问题,解决方案并不像在执行 new 之前增加一条 delete[] s 语句这样简单。 下面的代码并不足以解决 concat() 中的问题:

《C++编程风格(修订版)》——2.6 动态内存的回收

上面的 concat() 中有什么样的错误?假设 x 和 y 是 string 类的实例,并且我们通过表达式 x.concat(y,x) 来调用 concat() 函数。那么,在 concat() 中,函数将通过两种方法来访问对象 x : this 指针和参数 b 都是指向 x。我们可以看到,在执行 concat() 时,x.s 指向的数组在通过 b.s 传 递给 strcpy() 之前,就已经通过 this->s 删除了。等到执行 strcpy() 时,字符数组已经释放了,甚 至还可能被 concat() 中的 new 进行了重新分配。

要改正 concat() 中的内存泄漏,delete 语句只能添加在新的字符串创建之后:

《C++编程风格(修订版)》——2.6 动态内存的回收

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

继续阅读