STL释放指针元素时造成的内存泄露

当我们删除一个指针时,会删除该指针所指向的对象。但是当STL容器中存放指针对象时却不会这样。

1
2
3
4
5
// delete一个指针,会将该指针所指向的对象删除
int x=10;
int *p= &x;
// delete删除一个指针只会删除指针指向内存空间,不会删除指针本身,该指针变为悬垂指针
delete p;

可以在STL容器中存放对象,也可以用来存放对象的指针,在STL对象调用clear()或者erase()时,如果容器内存放的是对象实体,会被删除,但是如果容器内存储的是对象指针,会造成内存泄露(只删除了指针,而指针所指向的对象并不会被删除)。

考虑下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// for(type varName:object)是C++11的新特性——范围for语句。
vector<string*> strVector;
// 在strVector中添加十个string对象,并将其初始化为HelloWorld
for(int index=0;index<10;++index)
strVector.push_back(new string("HelloWorld!"));
// 创建一个strVector的副本
vector<string*> strVectorCopy=strVector;
// 输出strVector中存放的指针地址和地址指向的对象
for(auto &index:strVector)
cout<<index<<"\t"<<*index<<endl;
// 释放strVector之前,strVector中元素的个数
cout<<"strVector.size: "<<strVector.size()<<endl;
// 调用clear()删除strVector中的所有元素
strVector.clear();
// 或者使用erase删除strVector中的元素
/*
for(vector<string*>::iterator index=strVector.begin();index<strVector.end();){
strVector.erase(index);
}
*/
// 释放strVector之后,strVector中元素的个数
cout<<"strVector.size: "<<strVector.size()<<endl;

// 输出strVectorCopy中所有对象(指针,即strVector中原本存放着的指针)和这些指针所指向的对象
for (auto &index:strVectorCopy)
cout<<index<<"\t"<<*index<<endl;

运行结果:
01

很显然可以从结果中看到,虽然我们调用strVector.clear()/erase()删除了所有对象(指针),(预计)并期望释放它们的内存,但是可以看到指针指向的对象却依然存在,发生了内存泄露。

STL容器中存放的指针所指向的对象不会随着clear()/erase()清除对象而自动释放。

因为clear()/erase()清除每个元素时会自动调用对象的析构函数释放对象,但是当容器中存储的是对象指针时,使用clear()只会调用指针的析构函数,而指针的析构函数什么也不做。所以就会发生内存泄露。

这时候就需要我们自己手动管理内存了。

我们可以用delete手动删除strVector中每个指针所指向的对象:

1
2
3
4
5
6
7
for(auto &index:strVector){
delete index;
}
// 或者使用迭代器的版本
for(vector<string*>::iterator index=strVector.begin();index<strVector.end();++index){
delete *index;
}

然后我们再输出strVectorCopy中指针指向的对象的值:

1
2
3
4
5
6
7
for(auto &index:strVectorCopy){
cout<<*index<<endl;
}
// 迭代器版本
for(vector<string*>::iterator index=strVectorCopy.begin();index<strVectorCopy.end();++index){
cout<<**index<<endl;
}

运行结果:
02

可以看到,strVector中存储的指针指向的对象都已经被释放,这时我们访问的是悬垂指针指向的内存块,其结果是未定义的。

在使用STL时,应该注意以下两点:

  • STL容器是以复制的方式工作的。当你把一个元素放入容器中,在容器中存放的实际上是这个元素的一个副本,副本所占的内存是STL容器自动分配的。当删除这个元素时,STL会自己调用该元素的析构函数来回收这些内存。
  • 如果把指针放入容器中,删除元素的时候容器只负责回收指针本身所占的内存,但不会回收指针所指向的内容。
全文完,若有不足之处请评论指正。
本文标题:STL释放指针元素时造成的内存泄露
文章作者:ZhaLiPeng
发布时间:2016年05月08日 13时51分
本文字数:本文一共有957字
原始链接:https://imzlp.me/posts/50773/
许可协议: CC BY-NC-SA 4.0
转载请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!