Обучение использованию умных указателей, на мой взгляд, является одним из самых важных шагов, чтобы стать компетентным программистом C ++. Как вы знаете, когда вы в какой-то момент создаете новый объект, вы хотите удалить его.
Одна проблема, которая возникает, состоит в том, что с исключениями может быть очень трудно убедиться, что объект всегда освобождается только один раз во всех возможных путях выполнения.
Это причина RAII: http://en.wikipedia.org/wiki/RAII
Создание вспомогательного класса с целью обеспечения того, чтобы объект всегда удалялся один раз во всех путях выполнения.
Пример такого класса: std :: auto_ptr
Но иногда вам нравится делиться объектами с другими. Его следует удалять только тогда, когда никто его больше не использует.
Чтобы помочь с этим, были разработаны стратегии подсчета ссылок, но вам все равно нужно помнить addref и выпускать ref вручную. По сути это та же проблема, что и new / delete.
Вот почему boost разработал boost :: shared_ptr, это умный указатель для подсчета ссылок, так что вы можете делиться объектами и не пропускать память непреднамеренно.
С добавлением C ++ tr1 теперь это добавляется и к стандарту c ++, но называется std :: tr1 :: shared_ptr <>.
Я рекомендую использовать стандартный разделяемый указатель, если это возможно. ptr_list, ptr_dequeue и т. д. являются специализированными контейнерами IIRC для типов указателей. Я их пока игнорирую.
Итак, мы можем начать с вашего примера:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
Проблема здесь заключается в том, что всякий раз, когда G выходит из области видимости, мы пропускаем 2 объекта, добавленных в G. Давайте перепишем его для использования std :: tr1 :: shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
Когда G выходит из области видимости, память автоматически восстанавливается.
В качестве упражнения, с которым я сталкиваю новичков в моей команде, я прошу их написать собственный класс умных указателей. Затем, когда вы закончите, немедленно откажитесь от класса и никогда не используйте его снова. Надеюсь, вы приобрели важные знания о том, как умный указатель работает под капотом. В действительности нет магии.