Java и С++ по проблеме разматывания стека
Насколько я знаю, в случае неперехваченного исключения С++ немедленно уничтожает локальные переменные, Java выпускает ссылки и оставляет остальную часть сборщика мусора.
Правильно ли это? В чем разница между Java и С++ по этой проблеме? другими словами, какой из этих двух языков считается лучшим с точки зрения проблемы разворота стека?:)
Ответы
Ответ 1
Я собираюсь получить пламя для этого, но...
С++ - это руки лучше, чем Java в стеке, разматывающие фронт - там просто нет конкурса. Деструкторы объектов С++ полностью уничтожают стек до тех пор, пока точка захвата не будет достигнута - изящно освободите все управляемые ресурсы по пути.
Как вы сказали, Java оставляет все это во власти не детерминированного сборщика мусора (в худшем случае) или в руках каких-либо явно созданных блоков finally, которые вы замусорили свой код (поскольку Java не поддерживает true RAII). То есть весь код управления ресурсами находится в руках клиентов каждого класса, а не в руках дизайнера классов, где он должен быть.
Тем не менее, на С++ механизм разворачивания стека функционирует нормально, если вы тщательно следите за тем, чтобы сами деструкторы не испускали исключений. После того, как у вас есть два активных исключения, ваша программа abort()
без прохождения идет (и, конечно, без увольнения любого из оставшихся деструкторов).
Ответ 2
Stack unwinding специально вызывает деструкторы всех полностью сконструированных объектов в цепочке вызовов вплоть до точки, где исключение поймано.
Java просто не имеет разбиения стека - он ничего не делает для объектов, если генерируется исключение. Вы должны сами обрабатывать объекты в блоках catch
и finally
. В основном это потому, что С# представил using
statement - они упрощают вызов IDisposable.Dispose(), но опять же, что не полная замена для стека C++.
Ответ 3
Вы совершенно правы, С++ уничтожает все локальные переменные в обратном порядке, поскольку он выходит из каждой функции в стеке - так же, как если бы вы программно выполняли возврат - и из main()
.
Ответ 4
Для стека оба они одинаковы: они освобождают стек для блоков, которые вы оставляете с исключением. В Java все примитивные типы (int, double и т.д.) Сохраняются напрямую, в этот момент публикуются локальные переменные этого типа. Все объекты сохраняются через ссылки в локальных переменных, поэтому ссылки удаляются, но сами объекты остаются в куче. Если это была последняя ссылка на объект, они будут выпущены в следующей сборке мусора. Если в С++ созданы объекты в куче, а локальные переменные содержат указатель, объекты в куче не будут выпущены автоматически, они останутся на куче навсегда (да, вы получите ПАМЯТЬ ПАМЯТИ). Если вы сохранили объекты в стеке, тогда деструктор вызывается (и может освобождать другие ссылочные объекты в куче).