0

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

4 回答 4

4

一如既往的老规矩

每一个都new应该伴随着一个delete

在您的情况下,您调用的唯一时间new是分配一个实例Test(目前尚不清楚您为什么要这样做,但让我们忽略它)。然后将该对象的副本vector插入到; 您没有为插入的对象分配内存。所以没有必要调用deletevector.

另一方面,您正在泄漏内存,因为您从未调用delete过您分配的内存。添加一个

delete t;

在你完成使用后的某个地方的代码中t


现在,如果您的向量被声明为,则vector<Test *>需要在delete将元素从向量中删除之前手动操作。但是,如果您需要指针向量,您应该始终使用vector<unique_ptr<Test>>(或其他一些智能指针,或),在这种情况下,不需要手动调用。boost::ptr_vectordelete

于 2013-07-25T22:12:36.217 回答
4

Test* t = new Test("hi", 5);

您正在泄漏此对象。您将对象的副本存储到 中vector,但之后您不会释放原始对象。

v.insert(v.end(), *t);

改为使用v.push_back(*t)

if (it->id == 5);

分号是错误的。您需要将其删除。

测试* ptr = &*it; v.擦除(它);删除指针;

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;
    }
    

仅供参考,您可以考虑使用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);
}
于 2013-07-25T22:16:43.037 回答
2

用理智的 C++ 编写代码的正确方法是这样的:

int main()
{
    std::vector<Test> v { Test(""hi", 5) };

}   // returns 0, frees all allocated resources
于 2013-07-25T22:23:24.120 回答
2

矢量::擦除

从向量中删除单个元素(位置)或一系列元素([first,last))。

这通过删除的元素数量有效地减小了容器大小,这些元素被破坏了。

所以你只需要使用擦除功能。您不需要使用指针和删除。

请注意,当您将新实例插入向量时:

v.insert(v.end(), *t);

该类是在 vector 中再次复制构造的,因此您留下了两个单独的实例,一个 int和一个 in v[0]

于 2013-07-25T22:10:51.683 回答