Когда я должен использовать вектор объектов вместо вектора указателей? - PullRequest
12 голосов
/ 24 февраля 2009

У меня есть коллекция полиморфных объектов, все они получены из моего класса Animal: Cat, Dog и MonkeyFish.

Мой обычный режим работы - хранить эти объекты в векторе указателей животных, например:

std :: vector my_vector;

my_vector.push_back( new Animal_Cat() );
my_vector.push_back( new Animal_Dog() );
my_vector.push_back( new Animal_MonkeyFish() );

А жизнь прекрасна ... или это так?

Мне недавно сказали, что я действительно должен стараться избегать выделения памяти таким способом, потому что это делает управление памятью рутиной. Когда мне нужно уничтожить my_vector, я должен пройти через все элементы и удалить все.

Я не думаю, что могу хранить вектор ссылок (я могу ошибаться), поэтому мне кажется, что хранить вектор объектов Animal - моя единственная альтернатива.

Когда я должен выбрать использование вектора указателей против вектора объектов? В общем, какой метод предпочтительнее? (Я бы хотел максимально сократить копирование объектов.)

Ответы [ 4 ]

17 голосов
/ 24 февраля 2009

Вы должны использовать вектор объектов, когда это возможно; но в вашем случае это невозможно .

Контейнеры указателей позволяют избежать проблемы нарезки. Но тогда вы должны вызвать delete для каждого элемента, как вы делаете. Это раздражает, но возможно. К сожалению, бывают случаи (когда выдается исключение), когда вы не можете быть уверены, что удаление вызвано правильно, и в результате возникает утечка памяти.

Основным решением является использование умного указателя. Pre-C ++ 11 поставляется с auto_ptr, , но его нельзя использовать в стандартном контейнере . C ++ 11 имеет std::unique_ptr и std::shared_ptr, которые предназначены для использования в контейнерах (я предпочитаю std::unique_ptr, если мне действительно не нужен подсчет ссылок). Если вы не можете использовать C ++ 11, лучшим решением будет Повышение интеллектуальных указателей .

8 голосов
/ 24 февраля 2009

Вместо того, чтобы использовать shared_ptr со стандартными контейнерами STL, взгляните на Boost Pointer Container Library . Он предназначен для решения именно этой проблемы.

8 голосов
/ 24 февраля 2009

В этом случае сохранение вектора Animal не будет работать для вас, поскольку ваши животные имеют разные размеры, и вы не сможете хранить производные объекты в пространствах, предназначенных для хранения базового класса. (И даже если они имеют одинаковый размер, вы не получите желаемого полиморфного эффекта, так как будут выполняться методы базового класса - виртуальность метода не вступит в игру, если вы не получите к нему доступ через указатель или ссылку. )

Если вы хотите избежать раздражения, связанного с управлением памятью самостоятельно, вы можете хранить смарт-указатель, такой как shared_ptr (обратите внимание, что auto_ptr не работает с контейнерами STL по словам Макса Либберта) или какой-то его вариант. Таким образом, вы все еще можете использовать свой полиморфный класс, но для вас это немного меньше.

Нет никаких действительно жестких и быстрых правил относительно того, когда использовать объекты и указатели, хотя стоит отметить, что в некоторых случаях, как и у вас, объекты просто не будут работать для вас. Я склонен использовать объекты всякий раз, когда ничто не мешает этому, хотя, как вы заметили, вы должны быть обеспокоены дорогостоящими операциями копирования (хотя иногда их можно улучшить, передавая контейнеры по ссылке).

1 голос
/ 24 февраля 2009

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

  1. Нам не нужно беспокоиться о проблемах жизни указателей, что означает отсутствие утечек из этого конкретного кода (если, конечно, сами структуры не имеют данных указателя, но это уже другая история) .
  2. Расположение данных в смежных структурах в памяти повысит производительность в типичных сценариях использования, а не замедлит работу, как косвенное указание (условно говоря).

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

Однако при добавлении полиморфных объектов указатели необходимы, чтобы избежать нарезки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...