Если с учетом указателя mNext
узлы образуют цикл, то тогда уничтожение любого из узлов действительно вероятно сформирует бесконечный рекурсивный цикл, который завершит программу, взорвав стек.
То, что, вероятно, произойдет,
- Выдается первый "внешний"
delete node;
.
- При входе в деструктор узла еще ничего не делается, так как деструктор кода является «первой» вещью, выполняемой в процессе уничтожения (сам процесс уничтожения весьма сложен и включает в себя код деструктора, изменение класса, уничтожение члена, уничтожение базы в следующем порядке: см. этот ответ для более подробного объяснения ).
- Первая инструкция заполнения деструктора выполняет
delete mNext;
, тем самым запуская тот же процесс на следующем узле в цикле.
- Поскольку узлы образуют петлю, эта цепочка снова достигнет
node
«сзади», что сделает самый первый вызов рекурсией, которая никогда не закончится.
- Тем не менее каждый вызов будет выделять место в стеке для записи активации, поэтому через некоторое время вся память, разрешенная для использования для стека, будет исчерпана, и ОС уничтожит процесс. Вызов удаления не является «хвостовым вызовом», потому что после завершения кода деструктора память должна быть освобождена, поэтому эту рекурсию нельзя легко оптимизировать... в то время как
delete mNext;
является последним оператором в деструкторе, все же есть операции, которые должны быть выполнены после оператор delete
завершает работу.
Однако обратите внимание, что, по моему опыту, переполнение стека, если вы не используете специальные параметры компилятора, не будет проверяться, и поэтому завершение программы будет довольно «ненормальным». Также обратите внимание, что в Windows есть какой-то ужасный код, который в некоторых случаях скрывает ошибки segfault, если они происходят при завершении программы, поэтому вполне возможно, что программа Windows может просто изящно завершаться в этой операции, выполняемой после выхода из цикла событий.
Учтите, что переполнение стека обычно не рассматривается, на самом деле возможно любое поведение, включая очевидный «бесконечный цикл» (обратите внимание, что этот бесконечный цикл может быть не одним из рекурсивных деструкторов, а где-то внутри системы выполнения, которая сходит с ума из-за переполнения стека) .
Почему я использовал слово вероятно? Причина в том, что стандарт C++ говорит, что многократное уничтожение объекта является неопределенным поведением. Если вы добавите это к тому факту, что в C++ нет способа выйти из деструктора без завершения уничтожения, вы поймете, что компилятору теоретически разрешено помечать объект как «уничтожаемый» и заставлять демона вылетать из вашего nosrils, если дважды ввести деструктор одного и того же объекта. Однако проверка этой ошибки не является обязательной, и составители компиляторов часто ленивы (это НЕ оскорбление для программиста), и поэтому маловероятно, что эта проверка будет присутствовать (за исключением случаев, когда включена какая-то специальная дополнительная опция отладки).
Подводя итог: может ли это зацикливаться вечно? да. Может ли это рухнуть? Конечно. Может ли он перестать говорить мне, что объект уничтожается дважды? конечно. Может ли он просто красиво завершить программу (т.е. без установки кода ошибки)? да, это тоже.
Все может случиться. И Мерфи говорит, что произойдет то, что нанесет вам наибольший ущерб... например, программа будет завершаться каждый раз, пока вы ее разрабатываете... перед тысячей потенциальных клиентов.
Только не делай этого :-)
person
6502
schedule
25.09.2011
delete root
. Тогда деструктору не нужно проверять, является ли mPrevious нулевым, потому что, вероятно, он будет указывать на себя, когда его один элемент (или нулевой, тогда вам нужно проверить). Затем он должен сделатьmPrevious->mNext=0;
, так какmPrevious->mNext
должна быть текущей ссылкой, и вы уже удаляете ее (вы должны быть, если она находится в деструкторе). Затем, когда он дойдет до последнего, он удалит null, и ничего не произойдет, что не приведет к бесконечному циклу деструктора. - person   schedule 25.09.2011