2009-02-24 2 views
12

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

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

станд :: вектор < животных *> 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 является моей единственной альтернативой.

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

ответ

17

Вы должны использовать вектор объектов, когда это возможно; but in your case it isn't possible.

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

Главное решение заключается в использовании умного указателя. Pre-C++ 11 поставляется с auto_ptr, but that cannot be used in a standard container. C++ 11 имеет std::unique_ptr и std::shared_ptr, которые предназначены для использования в контейнерах (я предпочитаю std::unique_ptr, если мне действительно не нужен подсчет ссылок). Если вы не можете использовать C++ 11, лучшим решением будет Boost smart pointers.

+1

Ускоренные указатели Boost превратили его в технический отчет, поэтому у вас может быть std :: tr1 :: shared_ptr <>. VC++ 9 в VS 2008. –

+0

для справки C++ 0x unique_pte, который в значительной степени заменяет auto_ptr, будет работать в контейнерах из-за ссылок rvalue и семантики перемещения –

8

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

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

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

+0

Huh. Не знал этого. Как жаль. –

+0

Я никогда не пробовал, поэтому мне интересно, почему auto_ptr не работает с stl-контейнерами? –

+0

А, да. Имеет смысл. –

8

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

1

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

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

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

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

Смежные вопросы