博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
互相联系的 new 和 delete 要使用同样的形式
阅读量:2284 次
发布时间:2019-05-09

本文共 2041 字,大约阅读时间需要 6 分钟。

 
请观察下面的代码有什么不妥之处:
std::string *stringArray = new std::string[100];
...
delete stringArray;
一切似乎都按部就班, new 语句与 delete 相匹配。然而,这却是十分错误的。这段程序将出现无法预知的行为。最起码的是,由于该
stringArray
所指向的 100 个
string
对象中的
99
个没有被析构函数所析构,它们将很有可能得不到销毁。
 
当使用了一个
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;   //
删除一个对象数组
 
如果为
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++
库中包含了
string
vector
,使用这些模板可以摆脱动态分配数组的烦恼。比如说,在这里,
AddressLines
可以定义为一个字符串的向量,也就是
vector<string>
类型。
 
牢记在心
如果在一个
new
语句中使用了
[]
,那么必须要在相关的
delete
语句中使用
[]
。如果在
new
语句中没有使用
[]
,那么在相关的
delete
语句中一定不要出现
[]
 
 

转载地址:http://iuznb.baihongyu.com/

你可能感兴趣的文章
顺序表ADT模板设计及简单应用:将顺序表中前 m 个元素和后 n 个元素进行互换(数据结构OJ练习)(样例4553 WA)
查看>>
OJ平台各个简写的含义
查看>>
顺序表ADT模板及其简单应用算法设计:比较两个顺序表的大小(数据结构OJ练习)(RE 样例4555无法通过
查看>>
C++顺序表ADT模板简单应用算法设计:删除顺序表中的冗余元素(数据结构OJ)
查看>>
顺序表ADT模板简单应用算法设计:线性表的合并
查看>>
顺序表ADT模板简单应用算法设计:有序顺序表的提纯(我已经点了所有的测试样例)
查看>>
顺序表ADT模板简单应用算法设计:有序顺序表的合并
查看>>
顺序表ADT模板简单应用算法设计:在给定的有序顺序表中找出两个元素和为给定值的所有元素对
查看>>
顺序表ADT模板简单应用算法设计:在给定的顺序表中找出最大和最小的元素
查看>>
顺序表ADT模板简单应用出两个等长升序序列的中位数(大部分的样例都是有的,兄弟!)(我做错了,值得参考,这里不会删除重复的元素)
查看>>
顺序表ADT模板设计及简单应用:找匹配
查看>>
《计算机网络自顶向下方法》实验一——安装wireshark并访问网站观察其变化
查看>>
数据结构之链表的实现C++版(兄弟,请不要白嫖)
查看>>
C++中的“expected unqualified-id before delete”
查看>>
通过stringByTrimmingCharactersInSet去除字符串两端的特殊符号
查看>>
inputView与inputAccessoryView的使用,即自定义控件的响应视图
查看>>
ios开发中的常见问题
查看>>
IOS NSTimer 定时器用法总结
查看>>
iOS基于MVC的项目重构总结
查看>>
编程的智慧博文摘录
查看>>