Здравствуйте, MasterZiv, Вы писали:
>> В C++ вполне себе связаны. Раскрутка стека, или там зачистка >> объектов-членов в случае delete, вызывают исполнение деструкторов прямо >> во внутреннем контексте runtime'а.
MZ>Если одно является следствием другого, являются ли эти вещи связанными ? MZ>Знаешь, вопрос филосовский.
Вопрос очевидный. Деструктор тем и отличается от всех остальных функций-членов, что непосредственно вызывается в указанных выше случаях.
MZ>тем более что деструктор может быть вызван MZ>и НЕ в результате
Может, одно другому никак не мешает.
Re[3]: Вывод
От:
Аноним
Дата:
04.08.08 16:31
Оценка:
Здравствуйте, jazzer, Вы писали:
J>И не только это. J> * Деструктор инкапсулирует очистку, что само по себе хорошо: не возникает никаких левых внешних и взаимных зависимостей и прочие плюсы инкапсуляции. J> * Деструкторы вызываются только для уже сконструированных объектов (т.е. если к моменту выброса исключения какой-то обеъкт еще не создался, то его деструктор не вызовется). В ситуации с finally у тебя один блок на все объекты, а это означает, что придется городить какой-то огород вокруг твоих объектов, чтобы внутри finally понять, у кого звать деструктор, а у кого — нет. J> * Порядок вызова деструкторов устанавливается автоматически. В принципе невозможно "забыть" вызвать деструктор или позвать их не в том порядке. В случае с finally придется за всем этим следить руками.
Вот это САМОЕ ГЛАВНОЕ что я хотел услышать.
Re: Зачем нужен сборщик мусора? Как жить без деструкторов?
В С++ нет проблемы потерянного исключения, поскольку деструктору объекта запрещено выпускать наружу любые исключения (если это не так, то это UB, если мне не изменяет память), а вот в Java "потерять" исключение проще простого:
try
{
throw new FirstException();
}
finally
{
throw new SecondExpection(); // все, пользователь никогда не узнает о FirstException
}
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, jazzer, Вы писали:
J>И не только это. J> * Деструктор инкапсулирует очистку,
В managed-языках Вам также ничто не мешает инкапсулировать очистку в соответствующем методе. Более того, в отличии от C++, Вы при этом неограничены в использовании языковых конструкций. Например, можете спокойно бросать исключения...
J> * Деструкторы вызываются только для уже сконструированных объектов (т.е. если к моменту выброса исключения какой-то обеъкт еще не создался, то его деструктор не вызовется). В ситуации с finally у тебя один блок на все объекты,
Блоков будет столько, сколько Вы захочете. И логически правильный way — заводить по try/finally на каждый взятый ресурс. Если же хочется простоты, переходите на C#. Там IDisposable и using решают сей вопрос, и даже можно выбирать/комбинировать, в зависимости от условий, необходимое поведение: автоматику using, или возможности точного реагирования на исключения через try/catch/finally.
J> * Порядок вызова деструкторов устанавливается автоматически.
В случае нормальных вложенных try/finally/catch/using — аналогично.
J>В принципе невозможно "забыть" вызвать деструктор
Вопрос же "забыть" решается правильным инструментарием в IDE. Кстати, тоже преимущество managed-сред. Синтаксис C++ делает практически невозможным реализацию ПО типа ReSharper'а.
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Vamp, Вы писали:
V>А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?
Я тоже хотел бы услышать аргументацию drol-а на этот счет.
Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, drol, Вы писали:
D>Здравствуйте, jazzer, Вы писали:
J>>И не только это. J>> * Деструктор инкапсулирует очистку,
D>В managed-языках Вам также ничто не мешает инкапсулировать очистку в соответствующем методе. Более того, в отличии от C++, Вы при этом неограничены в использовании языковых конструкций. Например, можете спокойно бросать исключения...
Только я должен постоянно помнить о вызове метода "освобождения ресурсов". И при таком подходе, я запрасто могу скрыть первичное исключение, если вызов метода делаю в finally и этот метод бросает исключение.
J>> * Деструкторы вызываются только для уже сконструированных объектов (т.е. если к моменту выброса исключения какой-то обеъкт еще не создался, то его деструктор не вызовется). В ситуации с finally у тебя один блок на все объекты,
D>Блоков будет столько, сколько Вы захочете. И логически правильный way — заводить по try/finally на каждый взятый ресурс. Если же хочется простоты, переходите на C#. Там IDisposable и using решают сей вопрос, и даже можно выбирать/комбинировать, в зависимости от условий, необходимое поведение: автоматику using, или возможности точного реагирования на исключения через try/catch/finally.
Код кетода превращается в нечитабельный серпантин.
J>> * Порядок вызова деструкторов устанавливается автоматически.
D>В случае нормальных вложенных try/finally/catch/using — аналогично.
Опятьже, нечитаемая портянка.
J>>В принципе невозможно "забыть" вызвать деструктор
D>Вопрос же "забыть" решается правильным инструментарием в IDE. Кстати, тоже преимущество managed-сред. Синтаксис C++ делает практически невозможным реализацию ПО типа ReSharper'а.
C++ дает гораздо больше — гарантию вызова деструктора автоматического объекта. Кивать на IDE не имея гарантии со стороны языка — ну что же, аргумент, если других нет.
Вообщем, резюме такое: все проблемы GC сводяться к одной — к отсутствию понятия жизненного цикла объекта, а именно, недерминированному времени его кончины.
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Анатолий Широков, Вы писали:
АШ>В С++ нет проблемы потерянного исключения,
Вы всё перевернули с ног на голову. Это как раз в Java нет такой проблемы, бо как напишете, так и будет работать. Захотите ловить — будет ловить, захотите "терять" — будет "терять", захотите накапливать — будет накапливать и т.д.
А в C++ в этом случае Вас, практически всегда, ожидает только доблестный terminate()
АШ>поскольку деструктору объекта запрещено выпускать наружу любые исключения (если это не так, то это UB, если мне не изменяет память),
Изменяет.
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Vamp, Вы писали:
V>А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?
Излагаю n-дцатый раз:
Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?
В качестве ресурса пусть будет, например, распределённая транзакция. Требует нетривиальной очистки, в частности связанной с запросом новых ресурсов.
Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
D>Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?
Речь не мальчика, но мужа. Ответ: метод RAII применяется в том случае, где "не прошла" — либо не бывает, либо не предусматривает никакого исправления. Коммит в транзакции — НЕ RAII, потому что не прошедший коммит реально требует действия. Закрытия файлового дескриптора — вполне RAII, там сбоев не бывает.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Анатолий Широков, Вы писали:
АШ>В С++ нет проблемы потерянного исключения...., а вот в Java "потерять" исключение проще простого:
В С++ запросто можно написать подобный код
try
{
throw FirstException();
}
catch(...)
{
throw SecondExpection(); // все, пользователь никогда не узнает о FirstException
}
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
От:
Аноним
Дата:
04.08.08 18:55
Оценка:
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, Анатолий Широков, Вы писали:
АШ>>В С++ нет проблемы потерянного исключения...., а вот в Java "потерять" исключение проще простого:
S>В С++ запросто можно написать подобный код
S>
S>try
S>{
S> throw FirstException();
S>}
S>catch(...)
S>{
S> throw SecondExpection(); // все, пользователь никогда не узнает о FirstException
S>}
S>
и что?
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
А>>Зачем нужен сборщик мусора? RO>Для решения, в числе прочих, проблемы циклических ссылок. «Умные указатели» могут решить все проблемы, которые решает сборка мусора, кроме проблемы циклических ссылок.
даже умный указатель garbage_collected_ptr не решит эту проблему?
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Vamp, Вы писали:
D>>Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?
V>Речь не мальчика, но мужа. Ответ: метод RAII применяется в том случае, где "не прошла" — либо не бывает, либо не предусматривает никакого исправления. Коммит в транзакции — НЕ RAII, потому что не прошедший коммит реально требует действия.
Ну так и что Вы пишете на C++ в этом случае ?
V>Закрытия файлового дескриптора — вполне RAII, там сбоев не бывает.
Да ну... Например, если файловый дескриптор на самом деле указывает на сетевой ресурс, то во-первых и сбой возможен, а во-вторых нормальная информация о сбое вполне себе реально необходима.
Итого:
Подход с деструкторами-очистителями в C++ очень сильно ограничен, и нормально покрывает только самые простые (и по-большей части чисто технические) случаи, типа каких-нибудь smart pointer'ов. Любая очистка требующая новых ресурсов/допускающая отказы, сразу же вызывает тот жуткий код, который Вы напишете в ответ на вопрос из 1-го абзаца
*Кстати, обратите внимание на сам термин RAII == Resource Acquisition Is Initialization. Он ведь очень показателен, бо ни слова про какое-то там освобождение чего-бы то ни было не содержит. А всего лишь постулирует однофазный захват ресурса непосредственно при создании объекта
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, Анатолий Широков, Вы писали:
АШ>>В С++ нет проблемы потерянного исключения...., а вот в Java "потерять" исключение проще простого:
S>В С++ запросто можно написать подобный код
S>
S>try
S>{
S> throw FirstException();
S>}
S>catch(...)
S>{
S> throw SecondExpection(); // все, пользователь никогда не узнает о FirstException
S>}
S>
Есть разница, все же, между catch(...) и finally. catch(...) — я перехватываю все исключения и делаю это сознательно, finally — я попадаю сюда в независимости от того, было ли исключение или нет. Так вот, попав в finally по причине исключения я, выбросил SecondExpection, ввожу пользователя в заблуждение, поскольку он получит наведенное исключение, а не первопричину.
Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
drol пишет:
> Вопрос же "забыть" решается правильным инструментарием в IDE. Кстати, > тоже преимущество managed-сред.
Есть язык программирования, ценность которого заключается в
том, насколько в нём легко/удобно/правильно и т.п. работать программисту.
Если язык плохой, никакой IDE это не исправит, так что не надо
мешать мухи с котлетами.
Синтаксис C++ делает практически > невозможным реализацию ПО типа ReSharper'а.
Да думать надо, когда пишешь.
Posted via RSDN NNTP Server 2.1 beta
Re[6]: Зачем нужен сборщик мусора? Как жить без деструкторов
D>Ну так и что Вы пишете на C++ в этом случае ?
Напишу соответствующий код.
D>Да ну... Например, если файловый дескриптор на самом деле указывает на сетевой ресурс, то во-первых и сбой возможен, а во-вторых нормальная информация о сбое вполне себе реально необходима.
Ну и какое же там восстановление возможно? Вот стала у вас система раком и fclose возвращает ошибку. Что делать будете?
Да здравствует мыло душистое и веревка пушистая.
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Только я должен постоянно помнить о вызове метода "освобождения ресурсов".
Как мы уже установили в параллельной части треда: и в C++ Вы тоже обязаны помнить об освобождении ресурсов, чьё освобождение нельзя запихать в жёсткие ограничения деструктора.
*А вот в Java/C# Вас спасут IDEA/ReSharper
АШ>И при таком подходе, я запрасто могу скрыть первичное исключение, если вызов метода делаю в finally и этот метод бросает исключение.
Вы можете делать что угодно, в этом и преимущество. В C++ же у Вас, по-факту, только terminate()...
D>>Блоков будет столько, сколько Вы захочете. И логически правильный way — заводить по try/finally на каждый взятый ресурс. Если же хочется простоты, переходите на C#. Там IDisposable и using решают сей вопрос, и даже можно выбирать/комбинировать, в зависимости от условий, необходимое поведение: автоматику using, или возможности точного реагирования на исключения через try/catch/finally.
АШ>Код кетода превращается в нечитабельный серпантин.
Код будет таким, каким Вы захотите.
*Если у Вас используется 3+ вложенных ресурсов — это хороший повод задуматься над рефакторингом метода/архитектуры
АШ>C++ дает гораздо больше — гарантию вызова деструктора автоматического объекта.
Деструктора, который даже исключение не может бросить, дабы сообщить о проблемах очистки... Это не "больше", это "кандалы"...
АШ>Кивать на IDE не имея гарантии со стороны языка — ну что же, аргумент, если других нет.
*Не работавшим с IDEA/ReSharper, наверное, действительно понять сложно
Есть много синтаксических/семантических вещей, которые нужны в одних условиях, не требуются в других и избирательно необходимы в третьих. Причём срез этих условий может проходить по любой области: по стеку вызовов, по слоям стандартной библиотеки классов и т.д.
И лучше сделать язык/runtime удобным для различного рода инструментов а-ля ReSharper, чем пытаться сгородить язык/компилятор удовлетворяющий всей этой n-мерной массе противоречивых требований.
IDisposable-объекты, или там checked exceptions, например, как раз такой категории штуки...
АШ>Вообщем, резюме такое: все проблемы GC сводяться к одной — к отсутствию понятия жизненного цикла объекта, а именно, недерминированному времени его кончины.
Гы! Это не проблема, это решение проблемы.
GC управляет памятью, вот его предназначение. А жизненный цикл объектов это забота программиста, бо GC не знает смысла программы выше уровня языка. И вместо того чтобы дёргать какие-то там деструкторы вне нормального контекста исполнения программы (как поступает C++), managed-языки и -среды предоставляют набор вполне удобных механизмов — try/catch/finally/using — для нормального детерминированного управления объектом.
Re[6]: Зачем нужен сборщик мусора? Как жить без деструкторов
От:
Аноним
Дата:
04.08.08 20:36
Оценка:
Здравствуйте, drol, Вы писали:
D>Да ну... Например, если файловый дескриптор на самом деле указывает на сетевой ресурс, то во-первых и сбой возможен, а во-вторых нормальная информация о сбое вполне себе реально необходима.
Кто мешает использовать в этом случае обработчики завершения?
D>Итого:
D>Подход с деструкторами-очистителями в C++ очень сильно ограничен, и нормально покрывает только самые простые (и по-большей части чисто технические) случаи, типа каких-нибудь smart pointer'ов. Любая очистка требующая новых ресурсов/допускающая отказы, сразу же вызывает тот жуткий код, который Вы напишете в ответ на вопрос из 1-го абзаца
Так этих "самых простых" случаев — 95%, в оставшихся 5-ти используйте обработчики завершения, блоки try catch
Java
r1.open();
try {
r2.open();//вдруг при инициализации r2 возникнет исключение - надо закрыть r1try {
r3.open();//вдруг при инициализации r3 возникнет исключение - надо закрыть r1 и r2try {
//наконец-то делаем то, что хотели
......
}
finally {
r3.close();
}
}
finally {
r2.close();
}
}
finally {
r1.close();
}
ужасно выглядит!
c++
{
r1.open();
r2.open();
r3.open();
//делаем то, что хотим!!!
............
//метод close автоматически вызовется в деструкторах
}
В с++ в случаях удовлетворяющих идиоме RAII можно использовать деструкторы, в более сложных случах обработчики завершения, блоки try catch
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
Здравствуйте, MasterZiv, Вы писали:
>> Вопрос же "забыть" решается правильным инструментарием в IDE. Кстати, >> тоже преимущество managed-сред.
MZ>Есть язык программирования, ценность которого заключается в MZ>том, насколько в нём легко/удобно/правильно и т.п. работать программисту.
Язык программирования есть достаточно простая штука, условия же где он применяется на многие порядки разнообразней.
Например, у J2ME-приложений одни ограничения, правила хорошего тона и приёмы; у J2EE — другие; у Swing'а — третьи. И нормальная IDE позволяет настроить code inspector'ы соответственно окружению.
Более того, даже в рамках одной подплатформы навалом вариаций. Например, нормальная IDE, увидев в качестве target-устройства для J2ME-приложения Motorola iDEN v3.xx, включит дополнительные инспекторы, подсказывающие, что в этой прошивке есть баг, требующий после удаления элемента переоткрытия storage'а. Более того, нормальная IDE сумеет автоматически и корректно зарефакторить Ваш код связанный с этой проблемой...
MZ>Если язык плохой, никакой IDE это не исправит, так что не надо MZ>мешать мухи с котлетами.
Абсолютно верно. C++ нельзя исправить, уж слишком жуткий синтаксис
MZ>Синтаксис C++ делает практически >> невозможным реализацию ПО типа ReSharper'а.
MZ>Да думать надо, когда пишешь.
Наоборот! Надо делать так, чтобы не приходилось думать о такой ерунде.
Например, не надо думать о приоритете и порядке исполнения операций в выражении, надо совершенно тупо и без всякого думанья всегда ставить скобки. И тогда SMS-центр не будет лежать все выходные, от того что уставший и задёрганный к концу рабочего дня пятницы (не будем тыкать пальцем ) уже не мог думать какой приоритет у операции "меньше"...