Подтвердить что ты не робот

Когда следует использовать вектор объектов вместо вектора указателей?

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

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

std::vector < Animal * > 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 является моей единственной альтернативой.

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

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

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

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