避免C ++类中的内存泄漏

时间:2012-10-02 08:01:42

标签: c++ pointers memory-leaks unordered-map delete-operator

我已经使用以下头文件定义了一个C ++类:

class EarleyParser
{

    public:

        EarleyParser();
        virtual ~EarleyParser();

        void initialize( string filePath, bool probabilityParse );

    private:

        bool probabilityParser;

        typedef unordered_map< string, list<Production>* > productionHashTable;
        productionHashTable earlyHashTable;

};

正如您所看到的,该类的成员元素是unordered_map,其关键元素是字符串,而content元素是指向另一个名为Production的类的对象列表的指针(不记住它,它可能是任何东西)。

我的问题是我是否应该将它留给默认的析构函数来释放已分配的内存,或者我应该手动检查哈希表并删除它的所有元素。

在第二种情况下,程序是什么?为每个元素调用它都可以吗?

EarleyParser::productionHashTable::const_iterator got = this->earlyHashTable.find( "key" );
delete[] got->second;

6 个答案:

答案 0 :(得分:2)

如果您要存储指向地图中任何内容的指针,则必须手动浏览地图并删除每个指针。通常在类中你坚持使用RAII(资源获取是初始化)并在构造函数中构造东西并在析构函数中销毁

 for (;;)
     delete map->second; //it's not an array of lists 

然而,指向容器的指针不是一个好主意。你为什么需要一个指针?您尝试使用指向list

的指针来解决什么问题

使用像std::unique_ptr这样的智能指针比原始指针更好。原始指针应该是最后的手段,当你想不出更好的东西时,不是你抓住的第一件事。

答案 1 :(得分:2)

使用:

typedef unordered_map< string, std::unique_ptr<list<Production> > > productionHashTable;

代替。然后你不必担心管理内存。

答案 2 :(得分:2)

您需要澄清谁拥有list<Production>拥有的EarlyParser个对象。如果EarlyParser拥有它们,那么您需要释放资源。您可以通过遍历列表并在每个解除引用的迭代器( delete)上调用delete[]来完成此操作。或者您可以存储unique_ptr<list<Production>>。另一方面,最简单的解决方案是存储list<Production>,除非你真的有很强的理由存储指针。

答案 3 :(得分:1)

编译器合成的析构函数不会删除您放置在地图中的动态分配列表,因此您必须自己完成。在这种情况下,您可以遍历地图并删除每个元素的second成员:

EarleyParser::~EarleyParser() {
  for ( productionHashTable::iterator i = earlyHashTable.begin(); i != earlyHashTable.end(); ++i )
    delete i->second;
}

更好的方法是将列表放在地图中,而不是指向列表的指针。在这种情况下,编译器会自动处理销毁,如:

typedef unordered_map< string, list<Production> > productionHashTable;

答案 4 :(得分:1)

Unordered_map's destructor实际上调用了它所拥有的对象的析构函数,这意味着将调用list的析构函数。 The destructor of std::list有这样的说明:

  

注意,如果元素是指针,则不会销毁指向的对象。

所以这意味着,你必须自己清除记忆。是的,通过容器并删除元素1by1是好的。正如其他回答者所提到的那样,持有像这样的指针并不是一个好主意。

答案 5 :(得分:1)

由于您正在使用指向std::list的原始指针,因此您必须在地图生命周期内或在析构函数中清除EarleyParser对象时自行删除它。 / p>

你可以在你的析构函数中使用这样的东西:

for ( auto it = productionHashTable.begin();
      it != productionHashTable.end(); ++it )
{ 
    delete it->second;
}
productionHashTable.clear()

请注意,最后一行并不是绝对必要的,因为它会被清除,因为EarleyParser对象被破坏了,但显然你删除后不能使用地图中的值!