У меня есть объект, который потенциально может оказаться в нескольких списках.
Например
std::list<object*> lista = new std::list<object*>();
std::list<object*> listb = new std::list<object*>();
object* obj = new object();
lista->push_front(obj);
listb->push_front(obj);
Потенциально, есть много объектов, которые попадут в оба списка одинаково. Я понимаю, что умные указатели было бы легко сделать, но назовите меня мазохистом — я бы предпочел выяснить, как это сделать без.
В настоящее время я пробую эту технику:
td::list<object*>::iterator iter;
for(iter = lista->begin(); iter != lista->end(); iter++) {
delete (*iter);
*iter = 0;
}
std::list<object*>::iterator iterB;
for(iterB = listb->begin(); iterB != listb->end(); iterB++) {
if(*iterB != 0) {
delete (*iterB);
*iter = 0;
}
}
delete lista;
delete listb;
Но это нарушает мой эквивалент delete lista;
во время выполнения. Надеюсь, кто-то умнее насчет указателей может мне помочь. Заранее спасибо!
Постскриптум Я использую Windows 7 / MinGW.
Основная проблема заключается в том, что вы (по-видимому, вы не предлагаете полный код) delete
объект дважды: один раз при итерации по списку A и один раз при итерации по списку B.
Есть три основных решения:
Используйте умный указатель для подсчета ссылок, например std::shared_ptr
,
Рекомендуемые. Ваше заявление о том, что вы не хотите использовать умный указатель, похоже, сделано из-за невежества, а не из-за какого-то глупого менеджера.
Сохраните узлы также в первичном списке:
delete
узел, только когда вы знаете, что единственный список, в котором он все еще находится, является основным списком.
Реализуйте подсчет ссылок самостоятельно:
Самое простое — снова использовать существующее библиотечное решение, такое как boost::intrusive_ptr
, но все, что вам нужно сделать, это тщательно поддерживать счетчик ссылок в каждом узле. delete
когда счетчик ссылок уменьшается до 0.
Четвертая возможность — использовать сборщик мусора, такой как сборщик Boehm, но тогда для его поддержки необходимо структурировать код. Или, по крайней мере, это мое впечатление. И может быть трудно получить помощь в этом, так как очень немногие программисты на C ++ используют этот подход (что указывает на то, что он не совсем свободен от проблем).
использование shared_ptr
или иметь основной список с unique_ptr
,
В противном случае имейте основной список, которому принадлежат указатели, и удаляйте из него после очистки, но не удаляйте все остальные списки.
В противном случае, не удаляйте напрямую из списка напрямую. Вместо insert
указатели, которые вы хотите, вошли в std::set
и либо удалите их из других списков перед удалением (выполните итерацию и найдите в наборе), либо накопите все указатели, которыми вы хотите избавиться, затем массово удалите их из набора.
Это в грубом порядке suckitude по абзацу.
Не уверен, почему вы не хотите использовать shared_ptr. Хорошо, оденься. Как насчет того, чтобы просто создать локальный shared_ptr? Если нет, тогда загрузите оба списка в один основной список. Очистите два подсписка и удалите каждый элемент в основном списке, а также очистите основной список.
В соответствии
if(*iterB != 0) {
* iterB никогда не будет 0. Так что вы дважды удаляете.
Добавить счетчик поля к вашему object
, По умолчанию инициализировать до 0. Добавить +1 при добавлении в список. -1 при удалении из списка. Если counter==0
удалите object
,
Это не потокобезопасно, так как shared_ptr
, но это может быть намного быстрее по той же причине.