class A { ... };Главное - не забыть уничтожить удаляемые из контейнера объекты. И если делать это через оператор
class B : public A { ... };
std::vector<A*> BunchOfObjects;
BunchOfObjects.push_back(new B);
delete
- еще про виртуальный деструктор у базового класса не забыть бы.Хотя... другое классическое решение позволяет обойтись и без первого и без второго:
std::vector< boost::shared_ptr<A> > BunchOfObjects;Наличие виртуального деструктора в таком случае не принципиально - shared_ptr запоминает как нужно удалять объект, по умолчанию это будет оператор delete для нужного типа. Таким образом можно хранить, например, список динамически созданных окон - предков ATL::CWindow. Более того, если от хранимых объектов нужна лишь возможность их в нужный момент удалить, то можно вообще не задумываться от их типе используя boost::shared_ptr<void>.
BunchOfObjects.push_back(boost::shared_ptr<A>(new B));
6 комментариев:
Прикольно, не знал что shared_ptr может обходиться и без виртуального деструктора. Пришлось проверить, что бы убедиться :)
Кстати, в последнем варианте наверно имелось ввиду BunchOfObjects.push_back(boost::shared_ptr< A >(new B));?
Да, в последнем варианте должно быть именно так, как ты написал. Там explicit конструктор.
Ну если использовать boost, тогда почему бы и сразу не boost::ptr_container, которая берет всю работу с умными указателями на себя, работает быстрее чем вышеприведенное решение, и кроме того позволяет удобно обращаться к элементам, хранящимся в контейнере?
boost::ptr_container не хранит для каждого объекта его deleter, то есть подойдет только если есть виртуальный деструктор у базового класса. Конечно, если виртуальный деструктор у базового класса есть - то ptr_containers - самый лучший выбор (если не нужно делить ни с кем владение объектами, конечно).
Так - BunchOfObjects.push_back(boost::shared_ptr< A >(new B)) лучше не писать.
Привожу дословно из документации shared_ptr:
void f(shared_ptr< int >, int);
int g();
void ok()
{
shared_ptr< int > p(new int(2));
f(p, g());
}
void bad()
{
f(shared_ptr< int >(new int(2)), g());
}
Документация описывает пример, в котором может возникнуть последовательность вычисления операндов: operator new, g() /*can throw*/, shred_ptr конструктор. Цитирую:
Since function arguments are evaluated in unspecified order, it is possible for new int(2) to be evaluated first, g() second, and we may never get to the shared_ptr constructor if g throws an exception.
В случае с push_back() операнд всего один и между operator new и конструктором shared_ptr ничего может кинуть исключение. Разве что push_back имеет второй аргумент со значением по умолчанию, конструктор которого может упасть. Но стандарт не предполагает второго аргумента у std::vector::push_back(). Так что все нормально.
Отправить комментарий