1

我用以下头文件定义了一个 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,其关键元素是字符串,内容元素是指向另一个名为的类的对象列表的指针Production(不要介意,它可以是任何东西)。

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

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

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

6 回答 6

2

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

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

然而,指向容器的指针不是一个好主意。为什么需要指针?您要使用指向 a 的指针来解决什么问题list

使用类似的智能指针std::unique_ptr是比原始指针更好的主意。原始指针应该是最后的手段,而不是当你想不出更好的东西时你抢的第一件事。

于 2012-10-02T08:06:50.270 回答
2

用一个:

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

反而。然后你就不用担心管理内存了。

于 2012-10-02T08:07:31.533 回答
2

您需要明确谁拥有 . 拥有的list<Production>对象EarlyParser。如果EarlyParser拥有它们,那么您需要释放资源。您可以通过遍历列表并调用delete每个取消引用的迭代器 ( not delete[] ) 来实现。或者您可以unique_ptr<list<Production>>改为存储。另一方面,最简单的解决方案是存储list<Production>,除非您确实有非常充分的理由存储指针。

于 2012-10-02T08:08:31.497 回答
1

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

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

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

typedef unordered_map< string, list<Production> > productionHashTable;
于 2012-10-02T08:08:20.467 回答
1

Unordered_map 的析构函数实际上调用了它拥有的对象的析构函数,这意味着list将调用 s 的析构函数。 std::list 的析构函数有这个注释:

请注意,如果元素是指针,则不会破坏指向的对象。

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

于 2012-10-02T08:09:21.397 回答
1

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

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

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

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

于 2012-10-02T08:10:02.000 回答