Есть много проблем с вашим кодом, но я постараюсь охватить их все, не выкидывая исправленный список кода, и, надеюсь, вы сможете решить проблемы, основываясь на моих описаниях.
Прежде всего,нет необходимости заново изобретать «колесо» связанного списка, так как std :: list даст вам все, что вы пытаетесь сделать с вашим классом AccountList, но для этого вам нужно познакомиться с итераторами.По сути, итераторы - это то же самое, что и указатели, но я допускаю, что они могут сбить с толку тех, кто имеет опыт работы с Си.В любом случае, оставшаяся часть моего обсуждения предполагает, что вы продолжаете использовать свой класс AccountList вместо использования std :: list.
Во-вторых, в ваших конструкторах Account и AccountList вы должны использовать списки инициализатора для инициализации вашегопеременные-члены, так как нет ничего о переменных, которые требуют каких-либо вычислений или сложной логики.Например, сделайте следующее:
Account()
: balance(0.0), accountNumber(0), next(NULL) {}
Теперь перейдем к фактическим ошибкам:
Когда вы выполняете outAccount.write (), вы пишете все содержимое acc3, включая его указатели.Эти указатели действительны только в этот момент и только для «list1».В следующий раз, когда вы запустите вашу программу, система может выделить что-то еще по этим адресам, и эти указатели не будут содержать объекты «Учетная запись» намного меньше тех же, что и раньше.Это важно понимать, когда вы переходите к inAccount.read (), где вы читаете старое содержимое объектов Account вместе со старыми значениями указателя.На данный момент эти адреса больше не действительны или, по крайней мере, не относятся к «list2».Это важно понимать, когда вы вызываете list2-> addNode (acc3).Теперь посмотрите на AccountList :: addNode ().Объект Account, который вы передаете, 'h', все еще содержит это старое значение указателя в своем поле 'next'.Ничто в коде, который читает в объекте Account, никогда не устанавливает его «next» в NULL, равно как и addNode ().Если вы не решите использовать std :: list <>, я бы порекомендовал вам запустить addNode (), вызвав h-> setNextAccount (NULL), прежде чем делать что-либо еще.Это устраняет устаревшую ошибку указателя.
Прежде чем перейти к следующей ошибке, я хотел бы упомянуть, что AccountList :: addNode () является временной сложностью O (n).При увеличении размера вашего AccountList сканирование займет все больше и больше времени до конца списка, чтобы просто добавить следующий объект Account в список.Вы можете сделать лучше: если вы настаиваете на добавлении следующей учетной записи в конец AccountList, то сохраняйте указатель в AccountList не только для заголовка, но и для хвостового узла.Таким образом, addNode () будет иметь временную сложность O (1).В качестве альтернативы, добавьте новый объект Account в начало списка: установите новый объект «next» для текущего заголовка, затем измените «head», чтобы быть вновь добавленным Account (таким образом, значительно упрощается логика для добавления нового объекта Account).к списку).Обратите внимание, что поиск учетной записи по номеру учетной записи по-прежнему будет осуществляться по порядку O (n), и если ваше программное обеспечение обрабатывает тысячи учетных записей, это довольно плохая производительность для поиска учетной записи.Вы можете получить O (log n) время поиска аккаунта, если используете std :: map.В этом случае ваше время «addNode» также будет O (log n), что хуже, чем O (1), но чем вы будете заниматься чаще, добавляя учетные записи или просматривая существующие учетные записи?Вероятно, поиск существующих учетных записей.
ОК, теперь следующая ошибка: в main (), когда вы проверяете условия выхода цикла inAccount.read () в первый раз, вы не читали даже в первомзапись.Думаю, ничего страшного, но когда вы, наконец, прочитали последний, inAccount.eof () еще не соответствует истине, поэтому вы снова вводите тело цикла, но на этот раз inAccount.read () ничего не читает.Так что acc3 не изменился с последней итерации.Затем вы по-прежнему вызываете list2-> addNode (acc3), даже если вы ничего не читали.Вы добавляете последнюю запись дважды!Я дам вам понять, как решить эту проблему.
Наконец, у вас происходит очень страшное управление памятью / объектами. Обратите внимание, что вы никогда не удаляете два динамически размещенных списка учетных записей в main (). Это не так уж важно, если вы намереваетесь, чтобы ваши AccountLists автоматически восстанавливались системой при выходе из вашей программы, но если вы хотите иметь несколько AccountLists, которые время от времени приходят и уходят в жизни вашей программы, вам нужно убедитесь, что они удаляют свое содержимое. Похоже, что вы хотите, чтобы ваши объекты AccountList владели назначенными им объектами Account, поскольку в вашем деструкторе ~ AccountList () вы удаляете «главный» объект Account. Поскольку деструктор ~ Account () не удаляет объект «next», единственным объектом Account в списке, который будет удален, является главный Account. Поскольку AccountList имеет только указатель на головной объект, возможно, допустимое место для удаления остальной части списка будет в ~ Account (), как я вижу, вы подумали о том, чтобы сделать это на основе закомментированного вызова удаления. Как вы и думали, каждый объект Account мог бы удалить только свое собственное «next», но в этом подходе есть небольшая ошибка: каждое последующее удаление добавляет еще один вызов функции в стек времени выполнения, рекурсивно вызывая delete для каждой учетной записи в список, пока не дойдет до конца списка. Если у вас есть тысячи объектов Account, вы гарантированно увеличите свой стек во время выполнения. Лучший способ сделать это будет следующим:
~Account(){
Account *victim, *itsNext = next;
while (itsNext){
victim = itsNext;
itsNext = victim->next;
victim->next = NULL; // prevent recursion & blown stack
delete victim;
}
next = NULL;
}
Хммм ... Я вижу, у вас есть метод AccountList :: removeAll (), который, кажется, структурирован очень похоже на мой ~ Account () выше. Возможно, вы можете просто вызвать это из своего деструктора ~ AccountList ().
Теперь, если вы решите использовать std :: list или std :: map (я бы порекомендовал map), вам не нужно беспокоиться об утечках памяти или о том, как / когда удалять, если ваш std :: list или std :: map - это список или карта фактических объектов Account, поскольку при удалении записи списка / карты (с помощью erase () или при удалении всего списка / карты) охватываемый объект (ы) Account удаляется прямо вместе с этим. Если они представляют собой список или карту указателей учетной записи, вам все равно придется просмотреть их и удалить их вручную. Если вы не использовали список auto_ptrs или smart_ptrs, но я отвлекся.