释放STL向量中的对象

时间:2013-07-25 22:04:22

标签: c++ object memory-leaks stl

我有以下示例来释放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)

还有内存泄漏。这样做的正确方法是什么?

4 个答案:

答案 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它们。你正试图释放你不拥有的记忆。

话虽如此,你有两个选择:

  1. 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;
    }
    
  2. 不要在向量中存储指针:

    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;
    }
    
  3. 仅供参考,您可以考虑使用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)

vector::erase

  

从向量中移除单个元素(位置)或一系列元素([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