如何delete 指针vector中new出来的内存(之前说的方法不管用TAT)?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何delete 指针vector中new出来的内存(之前说的方法不管用TAT)?相关的知识,希望对你有一定的参考价值。
最近在写A*算法,遇到一个问题,详细说来是这样的(源码太长我先说大概情况)
声明: vector<TAStarNode *> openlist; 是一个指针的vector
然后东西是这样放进去的:
有一个大的循环
TAStarNode * p=NULL;
while(!p)
p = new TAStarNode[8];
当然,接下来会给它们赋值。
然后用一个循环把这8个都取址之后push_back进openlist里边。
各种删除、修改处理
一直循环,也就是说,p指向的地址是不断改变的,而且中间还要用到那些点,没办法直接delete[] p。openlist中每个指针都只指向一个元素。
所以我就放在最后在一个函数SafeDel()里边delete全部了。查了些资料之后是这样子写:
iter=openlist.begin();
for(;iter!=openlist.end();)
delete *iter;
iter=openlist.erase(iter);
//erase会返回被删除迭代器后面那个
但是会卡住,调试发现是第一次执行到 delete *iter 就不会动了。。。。
另外,看了前面问的也试过这样
for(int i=0;i<openlist.size();i++) delete openlist[i];
结果也一样。。。在delete那里卡住走不下去,光标一直闪啊闪。。。
到底应该怎么删除呢?真的不想搞到内存泄露。。。
源码太长。。。连剩下字数只够放头文件。。。所以就不发上来了
你的动态内存申请了一份,你却释放了八次
你对动态内存的分配和释放的机制不理解。这是运行时错误。
你的这句代码“p= new TAStarNode[8];”其本质是这样的 从堆中分配 8*sizeof( TAStarNode)大小的内存,并且调用8次TASTarNode的构造函数,初始化你的动态内存。注意,分配内存是,相关的动态存储管理的数据结构(空闲链表或位图)记录了你申请的动态内存的首地址和大小。
而且,这片内存你再释放是只能释放一次,因为数据结构里就记录了这样一份首地址和大小。释放时,将自首地址起,连续的在数据结构中指定大小的内存归还给空闲存储区,然后调用析构函数。
我给你说一下delete和delete[]的区别,如果动态创建一个对象数组,用delete只能对数据中的第0个对象元素调用析构函数。其他不对象元素不可能调用。而delete[] 对所有数组中所有对象元素调用析构函数。如果你的数组中对象在创建时,其成员也是动态创建的,则用delete必然内存泄露。
你的这一句代码delete *iter;反复执行,多次释放动态内存,第二次循环时,必然错误。
如果你想编程进阶的话,不能只看编程书,操作系统,和数据结构必看。其实我就是当初看操作系统中动态存储管理,才理解这点的。追问
醍醐灌顶~感谢大侠不吝赐教,暑假果然还有一堆书要看。。。
说回来三楼wolibaba其实也表达这个意思吧
那么这样改:vector pt_to_del
p = new TAStarNode[8];
pt_to_del.push_back(p);
void TAStar ::SafeDel()
iter=pt_to_del.begin();
for(;iter!=pt_to_del.end();)
delete *iter;
iter=pt_to_del.erase(iter);
openlist.clear();
closelist.clear();
结果可以了!!十分感谢各位的支持
当然,接下来会给它们赋值。
然后用一个循环把这8个都取址之后push_back进openlist里边。
各种删除、修改处理
这个样子的话,只可以使用delete[] p,将所有分配的空间都释放掉。
这时如果delete (p+1),delete (p+2)。。。delete(p+7),都是
不对的,具体编译器会怎么处理这种情况,就不知道了。因为编译器“认为”
它没有分配(p+1)。
可以这么想:p=new xxx[8] 时,编译器将分配的内存的首地址和分配的字节数
存在了某个地方,以后删除的时候要从这里取回这些存储的信息,但是这里并
没有存储首地址为(p+1)。。。(p+7)的相关信息。就有可能删除出错。
后面的那些代码就是在删除(p+1)。。。(p+7)。
可以改作一次性删除delete[] 或者分配的内存时候单独分配。追问
我也想一次删掉啊。。。可是p一直变不能动它。。。
单独分配。。。8个点就要建8个指针耶。。。一改工作量就惊人的大了。。。我再想想
p是一个指针,指向一个TAStarNode数组。 你是想释放这里new的内存吧。
大的循环
TAStarNode * p=NULL;
while(!p)
p = new TAStarNode[8];
openlist.push_back(p);
最后时候,循环遍历删除即可。
关于删除有2个选择:
vector<TAStarNode *>::iterator it = openlist.begin();
for(; it != openlist.end(); it++)
TAStarNode* p = it;
delete [] p;
p = NULL;
openlist.clear();
-----------------------------------
vector<TAStarNode *>::iterator it = openlist.begin();
for(; it != openlist.end(); it++)
TAStarNode* p = it;
delete [] p;
p = NULL;
openlist.erase(it);
it = openlist.begin();
追问
it前边有个*吧~
我把那段贴进去了,然后是这个样子
void TAStar ::SafeDel()
cout::iterator it = openlist.begin();
for(; it != openlist.end(); it++)
TAStarNode* p = *it;
delete [] p;
p = NULL;
openlist.clear();
cout<<"end one"<<endl;//测试用
成功的话应该输出
end
end one的。。。
结果截个图:
重新定义一个指针 TAStarNode * p ;
for(;iter!=openlist.end();)
p = iter ;
delete p ;
openlist.erase(p);
追问
漏了iter++?
老实说同志和我一个想法。。。我一开始就是这么写的。。。可惜不行
如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉
如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉
在STL中容器是智能的,可以在容器销毁时自动调用容器里对象的析构函数来销毁容器存储的对象。
STL的容器虽然比较智能,但是没有智能到可以自动销毁new出来的指针对象。
所以在使用STL中的容器时,如果保存的是mew出来的对象的指针。如果在容器销毁之前没有把new出来的对象释放,会造成内存泄露。
解决方法版本一:
这种手工释放容器里new的对象不太可靠,菲异常安全的。如果在delete的时候爆出异常,那么还是会引起内存泄露。
解决方法二:
使用函数对象的方式,可以保证对象的安全销毁完,虽然在调用时需要指明函数对象类型,实现了适配器作用
但是这种方法需要公有继承,有个特殊情况,就是STL的string。
string是没有虚析构函数的,所以在作为基类时,在这个对象使用完析构时,会找不到对应的析构函数,这时的行为是未知的。
解决方法三:
把模板化放在类里面,重载()操作符前,由编译器自动判断调用者的类型,这样就可以避免公有继承这一步操作,也就实现了通用。但是却丢弃了可适配的能力。
最优的解决方法:
使用boost里的shared_ptr智能指针,通过其的自动计算引用计数的实现来,在使用STL容器保存new出来的对象指针时,超出作用域范围自动销毁智能指针里的对象,实现安全可靠高效的解决内存泄露方案。
总的来说,在使用STL容器存储new出来的对象的指针时,需要注意对象的析构销毁步骤。这一步是需要我们自己来管理的。
以上是关于如何delete 指针vector中new出来的内存(之前说的方法不管用TAT)?的主要内容,如果未能解决你的问题,请参考以下文章
❌❌vectorの奇技淫巧⭕⭕C++ vector 如何正确处理动态申请内存的元素