Лучший способ справиться с такими вещами - использовать стандартный контейнер вместо какой-то самодельной вещи, если у вас нет веских причин и вы не знаете, что делаете и почему...
std::vector‹>
std::list‹>
Но чтобы выбрать контейнер, важно знать, что вы делаете, каково должно быть время жизни.
@Jack - что бы вы ни делали, стандартные контейнеры волшебным образом не позаботятся о выделенных вручную объектах за вас. Это принципиально невозможно.
Вы должны изменить свой подход к проблеме, чтобы воспринимать проблему как «объекты, выделенные вручную». Как только вы совершите этот скачок и поймете, что это плохой путь, вы сможете выбирать между «они являются объектами-значениями» или «они должны управляться с помощью shared_ptr».
ПРИМЕР 1: использование shared_ptr для хранения новых объектов (это подход, который следует использовать, если копирование вокруг MyNode — плохая идея [производительность, собственные ресурсы, сохраненное состояние]):
void MyFunction()
{
typedef boost::shared_ptr<MyNode> NodePtr;
std::list<NodePtr> my_list;
my_list.push_back(NodePtr(new MyNode(args...)));
my_list.push_back(NodePtr(new MyNode(args...)));
...
// when this function exits, the nodes, which are owned by shared_ptr's
// which are themselves owned by a stack instance of std::list<>
// will be automatically deleted, no leaks anywhere...
}
EX2: Это то, что вы делаете, если ваши узлы дешевы, их можно рассматривать как копируемые объекты (семантика значений):
void MyFunction()
{
std::vector<MyNode> my_list;
my_list.push_back(MyNode(args...));
my_list.push_back(MyNode(args...));
...
// when this function exits, the nodes, which are shored directly as copies
// in the vector container, will be automatically deleted, no leaks anywhere...
}
И если вы действительно по какой-то причине предпочитаете управлять экземплярами вручную (обычно вы делаете это, потому что время жизни на самом деле не привязано к времени жизни одного контейнера, а имеет некоторый нерегулярный жизненный цикл, который не может быть аккуратно инкапсулирован ничем, кроме пользовательского алгоритма):
void MyFunction()
{
std::list<MyNode*> my_list;
my_list.push_back(new MyNode(args...));
my_list.push_back(new MyNode(args...));
...
// we must manually deallocate the nodes because nothing else has been given
// responsibility anywhere (we're manually managing them)
typedef std::list<MyNode*>::iterator iterator;
for (iterator it = std::begin(my_list), end = std::end(my_list); it != end; ++it)
delete *it; // manually releases our allocated memory from the heap
// the "head" is still deleted automatically because it is stack allocated
// (the list object)
}
person
Mordachai
schedule
19.11.2011
unique_ptr
s узлов.) - person Kerrek SB   schedule 20.11.2011unique_ptr
или подобного в реализации связанного списка, как правило, очень плохая идея, потому что, когда вы уничтожаете голову, деструкторы каждого узла, в свою очередь, неизбежно в конечном итоге вызовут друг друга рекурсивно. Таким образом, размер вашего контейнера фактически ограничен размером вашего стека, хотя вы не узнаете об этом до времени очистки, когда ваш процесс взорвется. Это случай, когда вы хотите управлять им с уникальным правом собственности и использовать циклическую рекурсию для удаления. - person Steve Jessop   schedule 20.11.2011