указатели — избежать утечки памяти в классе C ++

Я определил класс 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;

1

Решение

Вам необходимо уточнить, кому принадлежит list<Production> объекты, принадлежащие EarlyParser, Если EarlyParser владеет ими, то вам нужно освободить ресурсы. Вы можете сделать это, перебирая список и вызывая delete на каждый разыменованный итератор (не delete[]). Или вы можете хранить unique_ptr<list<Production>> вместо. С другой стороны, самое простое решение — хранить list<Production> если у вас действительно нет очень веских причин для хранения указателей.

2

Другие решения

Если вы собираетесь хранить указатели на что-либо на своей карте, вам придется вручную просмотреть карту и удалить каждый из них. Обычно в классе вы придерживаетесь RAII (Resource Acquisition is Initialization) и конструируете вещи в конструктор и уничтожить в деструктор

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

Однако указатель на контейнер НЕ является хорошей идеей. Зачем вам нужен указатель? Какую проблему вы пытаетесь решить, используя указатель на list?

Использование умного указателя, такого как std::unique_ptr это гораздо лучшая идея, чем сырые указатели. Необработанные указатели должны быть последним средством, а не первым, что вы берете, когда не можете придумать ничего лучшего.

2

Использовать:

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

вместо. Тогда вам не нужно беспокоиться об управлении памятью.

2

Деструктор, синтезированный компилятором, не будет удалять динамически размещенные списки, которые вы поместили на карту, поэтому вы должны сделать это самостоятельно. В этом случае вы можете просто перебрать свою карту и удалить second член каждого элемента:

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

Лучшим подходом было бы размещать списки на карте, а не указатели на списки. В этом случае компилятор автоматически позаботится об уничтожении, как в:

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

Деструктор Unordered_map на самом деле вызывает деструкторы объекта, который он имеет, что означает, что деструктор listбудет называться
Деструктор std :: list имеет это примечание:

Обратите внимание, что если элементы являются указателями, объекты, на которые указывает указатель, не уничтожаются.

Таким образом, это означает, что вам придется очистить эту память самостоятельно. Да, пройти через контейнер и удалить элементы 1by1 можно. Как отмечали другие респонденты, держать указатели в таком виде не очень хорошая идея.

1

Поскольку вы используете необработанный указатель на std::list вам придется удалить его самостоятельно во время жизненного цикла карты или при очистке EarleyParser объект в его деструкторе.

Вы можете использовать что-то вроде этого в вашем деструкторе:

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

Обратите внимание, что последняя строка не является строго необходимой, так как она будет очищена в любом случае, так как EarleyParser объект уничтожен, но очевидно, что вы не должны использовать значения на карте после того, как удалили их!

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector