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

来源:互联网 发布:企业网络专线价格 编辑:程序博客网 时间:2024/05/17 15:40
请观察下面的代码有什么不妥之处:
std::string *stringArray = new std::string[100];...delete stringArray;

似乎没问题, new语句与delete相匹配。然而这完全错误。这段程序将出现无法预知的行为。最起码的是,由于该 stringArray 所指向的 100 个 string 对象中的 99 个没有被析构函数所析构,很有可能没被销毁。
 
当你使用new(即使用 new 动态创建了一个对象),将发生两件事情。第一,分配内存(通过一个名为 operator new 的函数,参见第 49 和51 条)。第二,针对此内存调用一个或多个构造函数。当你使用了一个 delete 语句时,将会发生另外两件事情:第一,为分配的内存调用一个或多个析构函数。第二,释放内存(通过 operator delete 函数实现,参见第 51 条)。 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 使用“ [] ”将会发生什么呢?同样结果未定义。由于它没有调用足够的析构函数,便造成内存泄漏。对于没有析构函数的内置数据类型,(如 int),同样也会出现无定义行为。
 
规则很简单:如果在一个 new 语句中使用了 [] ,那么必须在相关的 delete 语句中也使用 [] 。反之亦然。
 
有时候会编写这样的类:它们包含用来动态分配内存的指针,并且提供多个构造函数。上述规则尤其重要。在所有的构造函数中,当编写初始化指针成员的语句时,你必须使用 new 的一致的格式。如果你不这样做,那么你怎么能知道析构函数中 delete 需要用什么样的格式呢?
当使用 typedef ,那么这一规则同样重要,因为它意味着 typedef 的创建者必须清楚:当 typedef 的类型中使用了 new 来创建对象,那么相应的 delete 语句中必须要使用同样的格式。请看下边的示例:
typedef std::string AddressLines[4];// 每个人的地址有 4 行, 每行都是一个字符串由于 AddressLines 是一个数组, 如果这样使用了 new :std::string *pal = new AddressLines;// 请注意“ new AddressLines ”// 返回一个 string* , 与“ new string[4] ”完全一样

那么 delete 就必须使用数组的格式:
delete pal;  // 将出现无法预知的行为!
delete [] pal;  // 工作正常
为了避免此类混淆,请谨慎使用 typedef 来定义数组。这十分简单,因为标准 C++ 库(参见第 54 条)中包含了 string 和 vector ,这些模板可将数组需求降为零。比如说,在这里, AddressLines 可以定义为一个字符串的向量,也就是vector<string> 类型。 需要记住的:如果在一个 new 语句中使用了 [] ,那么必须要在相关的 delete 语句中使用 [] 。反之亦然
0 0
原创粉丝点击