我有以下示例来释放STL向量中的对象。
#include <map>
#include <string>
using namespace std;
class Test
{
public:
char* name;
int id;
Test(char* n, int i);
};
Test::Test(char* n, int i)
{
name = n;
id = i;
}
int main ()
{
Test* t = new Test("hi", 5);
vector<Test> v;
v.insert(v.end(), *t);
for(vector<Test>::iterator it = v.begin(); it != v.end(); it++)
{
if (it->id == 5)
{
Test* ptr = &*it;
v.erase(it);
delete ptr;
break;
}
}
return 0;
}
根据我一直在研究的内容,应该是正确的方法。但是,valgrind给了我这个抱怨:
==7404== Invalid free() / delete / delete[]
==7404== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==7404== by 0x400FD2: __gnu_cxx::new_allocator<Test>::deallocate(Test*, unsigned long) (new_allocator.h:94)
==7404== by 0x401004: std::_Vector_base<Test, std::allocator<Test> >::_M_deallocate(Test*, unsigned long) (stl_vector.h:133)
==7404== by 0x401045: std::_Vector_base<Test, std::allocator<Test> >::~_Vector_base() (stl_vector.h:119)
==7404== by 0x40109C: std::vector<Test, std::allocator<Test> >::~vector() (stl_vector.h:272)
==7404== by 0x400998: main (test.cc:46)
==7404== Address 0x4C58070 is 0 bytes inside a block of size 16 free'd
==7404== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==7404== by 0x40098A: main (test.cc:41)
还有内存泄漏。这样做的正确方法是什么?
答案 0 :(得分:4)
这与旧的规则一如既往
每个new
每个delete
只有new
在你的情况下,你唯一一次调用Test
就是分配一个vector
的实例(并且不清楚你为什么要这样做,但让我们忽略它)。然后将该对象的副本插入delete
;你没有为插入的对象分配内存。因此,无需在由vector
管理的内存上调用delete
。
另一方面,你正在泄漏内存,因为你从未在你分配的内存上调用delete t;
。添加
t
完成后使用vector<Test *>
在代码中
现在,如果你的向量被声明为delete
,你需要手动vector<unique_ptr<Test>>
元素,然后才能从向量中删除它们。但是如果你需要一个指针向量,你应该总是使用delete
(或其他一些智能指针,或boost::ptr_vector
),在这种情况下,手动调用{{1}}是不必要的
答案 1 :(得分:4)
测试* t =新测试(“hi”,5);
您正在泄露此对象。您正在将对象的副本存储到vector
中,但之后您不会释放原始对象。
v.insert(v.end(),* t);
改为使用v.push_back(*t)
。
if(it-&gt; id == 5);
分号是错误的。你需要删除它。
测试* ptr =&amp; *它; v.erase(它); 删除ptr;
erase()
很好,但delete
不是。您没有在new
中存储使用vector
分配的对象,因此您根本不应该尝试delete
它们。你正试图释放你不拥有的记忆。
话虽如此,你有两个选择:
在vector
:
int main ()
{
Test* t = new Test("hi", 5);
vector<Test*> v;
v.push_back(t);
for(vector<Test*>::iterator it = v.begin(); it != v.end(); ++it)
{
Test* ptr = *it;
if (ptr->id == 5)
{
v.erase(it);
delete ptr;
break;
}
}
return 0;
}
不要在向量中存储指针:
int main ()
{
/*
Test *t = new Test("hi", 5);
vector<Test> v;
v.push_back(*t);
delete t; // don't forget this!
*/
vector<Test> v;
v.push_back(Test("hi", 5));
for(vector<Test>::iterator it = v.begin(); it != v.end(); ++it)
{
if (it->id == 5)
{
v.erase(it);
break;
}
}
return 0;
}
仅供参考,您可以考虑使用std::find_if()
而不是手动循环:
struct IsId
{
int _id;
IsId(int id) : _id(id) {}
bool operator()(const Test &src) const { return (src.id == _id); }
};
vector<Test>::iterator it = find_if(v.begin(), v.end(), IsId(5));
if (it != v.end())
{
v.erase(it);
}
答案 2 :(得分:2)
从向量中移除单个元素(位置)或一系列元素([first,last))。
这有效地减少了容器大小,删除了被删除的元素数量。
所以你必须使用擦除功能。你不需要使用指针并删除。
请注意,当您将新实例插入vector:
时v.insert(v.end(), *t);
该类是在向量中再次构建的,因此您将在t
中保留两个单独的实例,在v[0]
中保留一个实例。
答案 3 :(得分:2)
在理智的C ++中编写代码的正确方法是这样的:
int main()
{
std::vector<Test> v { Test(""hi", 5) };
} // returns 0, frees all allocated resources