Управление памятью на объектах в коллекции C ++ - PullRequest
3 голосов
/ 20 июля 2009

У меня есть карта, которая связывает целые числа с векторами (объектов). Эти векторы представляют собой набор задач для выполнения. Чтобы уменьшить количество копий при использовании этой карты и вектора, я настроил их на использование указателей.

std::map<int, std::vector<MyObject *> *> myMap;

Во время инициализации класса, который содержит myMap, я заполняю myMap, создавая новый вектор, заполненный новыми объектами MyObject.

Однако меня беспокоит управление памятью. Теперь у меня есть эти различные предметы, которые лежат где-то в куче, и я отвечаю за их очистку, когда я закончу с ними. Я также знаю, что НИКОГДА не закончу с ними, пока программа не закончится. Но как насчет 10 недель, когда кто-то решит, что умный способ изменить это приложение включает в себя удаление элементов с карты / векторов. Это может привести к утечке памяти.

У меня вопрос, как я могу обработать правильное освобождение этих объектов, чтобы даже если они были удалены через функцию STL, объекты успешно удалялись?

Ваша помощь очень ценится, дайте мне знать, если я пропустил что-то критическое! Спасибо!

Ответы [ 6 ]

7 голосов
/ 20 июля 2009

Используйте умное повышение указателя: shared_ptr, а не необработанные указатели, таким образом, когда объект уничтожается, он также очищает память, выделенную для кучи.

boost :: shared_ptr http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm

Также есть ли причина иметь указатели на векторы? Они почти не занимают места, и объекты в std :: map все равно не перемещаются (в отличие от объектов в векторе, которые перемещаются / копируются каждый раз, когда вектор перераспределяется, например, чтобы получить больше места).

EDIT: Также shared_ptr является компонентом tr1, и я уверен, что он находится в следующем стандарте, так что ваш компилятор может уже иметь его. Есть также много других умных указателей, которые безопасны для STL, чтобы дать вам представление о том, как написать свой собственный, быстрый поиск в Google должен найти их.

EDIT2: Только что проверил, и реализация TR1 для Visual Studio 2008 включает shared_ptr, который включен в Visual C ++ 2008 Feature Pack . Я ожидаю, что многие другие поставщики имеют реализации, доступные по крайней мере для частей TR1, поэтому, если вы не используете VS, поищите на сайте поставщиков поддержку TR1.

4 голосов
/ 20 июля 2009

Я согласен, что использование умных указателей - хороший способ, но есть как минимум две альтернативы:

а) Копирование может быть не таким дорогим, как вы думаете. Попробуйте реализовать карту значений

std::map<int, std::vector<MyObject>> myMap;

b) Замените вектор собственным классом, который обертывает вектор. В этом деструкторе классов, обработайте освобождение. Вы также можете предоставить методы для добавления и удаления MyObjects.

1 голос
/ 22 июля 2009

Спасибо всем за хорошие ответы. Я думаю, что в настоящее время я склоняюсь к решению вектора ценностей в настоящее время. Основная причина в том, что std :: auto_ptr не работает с коллекциями из-за того, что его нельзя скопировать. Это была бы единственная реализация умного указателя, которую я мог бы использовать, не проходя обременительный процесс проверки и не прокручивая свой собственный.

Хорошая новость заключается в том, что ваши ответы привели меня по очень хорошей дороге. Я узнал о RAII, об опасностях обработки исключений и о том, как их минимизировать, и вложил достаточно внимания в свой дизайн, чтобы я мог быть удовлетворен его «правильностью».

Прилагаются ссылки, которые я нашел полезными на этом пути. Я надеюсь, что любой, кто столкнется с подобной проблемой, найдет эти ссылки полезными.

Ресурс RAII
Умные указатели в C ++
Повышение интеллектуальных указателей
Дополнительные сведения о реализации интеллектуальных указателей * / 1017 *

1 голос
/ 20 июля 2009

Лучше всего использовать общий указатель (как предлагают другие).

Если вы действительно знаете, что никогда не будет сделано с ними, то технически они не требуют освобождения. Если это действительно желаемое поведение, просто запишите это, чтобы кто-то не пришел через 10 недель и принял это за настоящую утечку.

0 голосов
/ 22 июля 2009

Подробно о минимизации копирования при использовании map<,vector<Object>>:

Внимательно посмотрите на интерфейсы map и vector. Они в основном возвращают ссылки на содержащиеся элементы, и если вы сохраните ссылку при передаче этих вещей, копирование не будет.

Плохой пример:

std::vector<MyObject> find_objects( const std::map<int,std::vector<MyObject>> & map, int i ) {
    const std::map<int,std::vector<MyObject>>::const_iterator it = map.find( i );
    if ( it != map.end() )
        return it->second;
    else
        return std::vector<MyObject>();
}
// ...
const std::vector<MyObject> objects = find_objects(/*...*/);

Лучше:

const std::vector<MyObject> & find_objects( const std::map<int,std::vector<MyObject>> & map, int i ) {
    const std::map<int,std::vector<MyObject>>::const_iterator it = map.find( i );
    if ( it != map.end() )
        return it->second;
    static const std::vector<MyObject> none();
    return none;
}
// ...
const std::vector<MyObject> & objects = find_objects(/*...*/);

-> без копирования

0 голосов
/ 21 июля 2009

Если владение каждым указателем не распределяется между разными записями в векторах / картах, и вы имеете в виду только сокращение копирования, выполняемого во время вставки, тогда вам также следует рассмотреть библиотеку Pointer Container boost.

...