Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 16:31
Оценка:
Здравствуйте, MasterZiv, Вы писали:

>> В C++ вполне себе связаны. Раскрутка стека, или там зачистка

>> объектов-членов в случае delete, вызывают исполнение деструкторов прямо
>> во внутреннем контексте runtime'а.

MZ>Если одно является следствием другого, являются ли эти вещи связанными ?

MZ>Знаешь, вопрос филосовский.

Вопрос очевидный. Деструктор тем и отличается от всех остальных функций-членов, что непосредственно вызывается в указанных выше случаях.

MZ>тем более что деструктор может быть вызван

MZ>и НЕ в результате

Может, одно другому никак не мешает.
Re[3]: Вывод
От: Аноним  
Дата: 04.08.08 16:31
Оценка:
Здравствуйте, jazzer, Вы писали:

J>И не только это.

J> * Деструктор инкапсулирует очистку, что само по себе хорошо: не возникает никаких левых внешних и взаимных зависимостей и прочие плюсы инкапсуляции.
J> * Деструкторы вызываются только для уже сконструированных объектов (т.е. если к моменту выброса исключения какой-то обеъкт еще не создался, то его деструктор не вызовется). В ситуации с finally у тебя один блок на все объекты, а это означает, что придется городить какой-то огород вокруг твоих объектов, чтобы внутри finally понять, у кого звать деструктор, а у кого — нет.
J> * Порядок вызова деструкторов устанавливается автоматически. В принципе невозможно "забыть" вызвать деструктор или позвать их не в том порядке. В случае с finally придется за всем этим следить руками.

Вот это САМОЕ ГЛАВНОЕ что я хотел услышать.
Re: Зачем нужен сборщик мусора? Как жить без деструкторов?
От: Анатолий Широков СССР  
Дата: 04.08.08 17:24
Оценка:
В С++ нет проблемы потерянного исключения, поскольку деструктору объекта запрещено выпускать наружу любые исключения (если это не так, то это UB, если мне не изменяет память), а вот в Java "потерять" исключение проще простого:

try
{
    throw new FirstException();
}
finally
{
      throw new SecondExpection(); // все, пользователь никогда не узнает о FirstException
}
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Vamp Россия  
Дата: 04.08.08 17:29
Оценка:
А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 17:31
Оценка:
Здравствуйте, 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]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Анатолий Широков СССР  
Дата: 04.08.08 17:43
Оценка:
Здравствуйте, Vamp, Вы писали:

V>А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?


Я тоже хотел бы услышать аргументацию drol-а на этот счет.
Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Анатолий Широков СССР  
Дата: 04.08.08 17:59
Оценка:
Здравствуйте, 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]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 18:03
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>В С++ нет проблемы потерянного исключения,


Вы всё перевернули с ног на голову. Это как раз в Java нет такой проблемы, бо как напишете, так и будет работать. Захотите ловить — будет ловить, захотите "терять" — будет "терять", захотите накапливать — будет накапливать и т.д.

А в C++ в этом случае Вас, практически всегда, ожидает только доблестный terminate()

АШ>поскольку деструктору объекта запрещено выпускать наружу любые исключения (если это не так, то это UB, если мне не изменяет память),


Изменяет.
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 18:11
Оценка:
Здравствуйте, Vamp, Вы писали:

V>А вот тут много говорят о исключениях из деструктора. А я вообще-то не вполне понимаю, какой может быть смысл в исключениях, брошенных из деструктора. Объект умер, его уже не оживить. Что должно означать исключение с точки зрения логики программы?


Излагаю n-дцатый раз:

Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?

В качестве ресурса пусть будет, например, распределённая транзакция. Требует нетривиальной очистки, в частности связанной с запросом новых ресурсов.
Re[4]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Vamp Россия  
Дата: 04.08.08 18:16
Оценка: 1 (1) +2
D>Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?

Речь не мальчика, но мужа. Ответ: метод RAII применяется в том случае, где "не прошла" — либо не бывает, либо не предусматривает никакого исправления. Коммит в транзакции — НЕ RAII, потому что не прошедший коммит реально требует действия. Закрытия файлового дескриптора — вполне RAII, там сбоев не бывает.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: shrecher  
Дата: 04.08.08 18:49
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>В С++ нет проблемы потерянного исключения...., а вот в 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]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: sraider http://dvinogradov.blogspot.com
Дата: 04.08.08 19:05
Оценка:
А>>Зачем нужен сборщик мусора?
RO>Для решения, в числе прочих, проблемы циклических ссылок. «Умные указатели» могут решить все проблемы, которые решает сборка мусора, кроме проблемы циклических ссылок.

даже умный указатель garbage_collected_ptr не решит эту проблему?
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 19:41
Оценка: +2
Здравствуйте, Vamp, Вы писали:

D>>Оппоненты выдвигают тезис о деструкторе C++ как замечательном методе очистки/освобождения/деинициализации ресурса. Однако не могут ответить на элементарный вопрос: как вызывающему коду нормально узнать о том, что очистка/освобождение/деинициализация "не прошла" ?


V>Речь не мальчика, но мужа. Ответ: метод RAII применяется в том случае, где "не прошла" — либо не бывает, либо не предусматривает никакого исправления. Коммит в транзакции — НЕ RAII, потому что не прошедший коммит реально требует действия.


Ну так и что Вы пишете на C++ в этом случае ?

V>Закрытия файлового дескриптора — вполне RAII, там сбоев не бывает.


Да ну... Например, если файловый дескриптор на самом деле указывает на сетевой ресурс, то во-первых и сбой возможен, а во-вторых нормальная информация о сбое вполне себе реально необходима.

Итого:

Подход с деструкторами-очистителями в C++ очень сильно ограничен, и нормально покрывает только самые простые (и по-большей части чисто технические) случаи, типа каких-нибудь smart pointer'ов. Любая очистка требующая новых ресурсов/допускающая отказы, сразу же вызывает тот жуткий код, который Вы напишете в ответ на вопрос из 1-го абзаца

*Кстати, обратите внимание на сам термин RAII == Resource Acquisition Is Initialization. Он ведь очень показателен, бо ни слова про какое-то там освобождение чего-бы то ни было не содержит. А всего лишь постулирует однофазный захват ресурса непосредственно при создании объекта
Re[3]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Анатолий Широков СССР  
Дата: 04.08.08 19:43
Оценка:
Здравствуйте, 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]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: MasterZiv СССР  
Дата: 04.08.08 19:44
Оценка:
drol пишет:

> Вопрос же "забыть" решается правильным инструментарием в IDE. Кстати,

> тоже преимущество managed-сред.

Есть язык программирования, ценность которого заключается в
том, насколько в нём легко/удобно/правильно и т.п. работать программисту.
Если язык плохой, никакой IDE это не исправит, так что не надо
мешать мухи с котлетами.

Синтаксис C++ делает практически
> невозможным реализацию ПО типа ReSharper'а.

Да думать надо, когда пишешь.
Posted via RSDN NNTP Server 2.1 beta
Re[6]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: Vamp Россия  
Дата: 04.08.08 20:00
Оценка:
D>Ну так и что Вы пишете на C++ в этом случае ?
Напишу соответствующий код.

D>Да ну... Например, если файловый дескриптор на самом деле указывает на сетевой ресурс, то во-первых и сбой возможен, а во-вторых нормальная информация о сбое вполне себе реально необходима.

Ну и какое же там восстановление возможно? Вот стала у вас система раком и fclose возвращает ошибку. Что делать будете?
Да здравствует мыло душистое и веревка пушистая.
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 20:05
Оценка: 1 (1)
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Только я должен постоянно помнить о вызове метода "освобождения ресурсов".


Как мы уже установили в параллельной части треда: и в 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 возникнет исключение - надо закрыть r1
  try {
    r3.open();//вдруг при инициализации r3 возникнет исключение - надо закрыть r1 и r2
    try {
      //наконец-то делаем то, что хотели
      ......
    }
    finally {
      r3.close();
    }
  }
  finally {
    r2.close();
  }
}
finally {
  r1.close();
}

ужасно выглядит!

c++
{
  r1.open();
  r2.open();
  r3.open();
  //делаем то, что хотим!!!
  ............
  //метод close автоматически вызовется в деструкторах
}


В с++ в случаях удовлетворяющих идиоме RAII можно использовать деструкторы, в более сложных случах обработчики завершения, блоки try catch
Re[5]: Зачем нужен сборщик мусора? Как жить без деструкторов
От: drol  
Дата: 04.08.08 20:40
Оценка:
Здравствуйте, 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-центр не будет лежать все выходные, от того что уставший и задёрганный к концу рабочего дня пятницы (не будем тыкать пальцем ) уже не мог думать какой приоритет у операции "меньше"...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.