Здравствуйте, Pzz, Вы писали:
S>>В итоге, операции со счетчиком ссылок занимают пару ассемблерных инструкций.
Pzz>Эта пара инструкций на SMP-системе займет целую вечность из-за необходимости синхронизации кешей процессоров.
Лучше ссылок еще не придумали.
Re[15]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, Cyberax, Вы писали: D>>Причём здесь finalizer-то ??? Dispose() это обычный метод, и вызывается в обычном контексте исполнения. C>Ну ладно. Кинешь исключение из Dispose(). Какой в этом смысл?
Очень простой в этом смысл: сообщаем вызывающему, что детерминистическая финализация не удалась.
К примеру, при закрытии файла не удается сделать flush по причине отсутствия доступа к устройству.
В отличие от C++, имеем детерминированный способ обработать эту ситуацию. К примеру, попробовать открыть файл на другом устройстве и повторить операцию записи, которая была прервана исключением.
C>Просто единственное ограничение — это не выбрасывать другое исключение за пределы дестркуктора.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, Sinclair, Вы писали:
D>>>Причём здесь finalizer-то ??? Dispose() это обычный метод, и вызывается в обычном контексте исполнения. C>>Ну ладно. Кинешь исключение из Dispose(). Какой в этом смысл? S>Очень простой в этом смысл: сообщаем вызывающему, что детерминистическая финализация не удалась. S>К примеру, при закрытии файла не удается сделать flush по причине отсутствия доступа к устройству. S>В отличие от C++, имеем детерминированный способ обработать эту ситуацию. К примеру, попробовать открыть файл на другом устройстве и повторить операцию записи, которая была прервана исключением.
Ну вот допустим, что есть такой код на C#:
using(file1 = new File(...))
using(file2 = new File(...))
using(file3 = new File(...))
{
...bla-bla-bla...
}
При выходе из блока кода метод Dispose вызывается у file3. И кидает исключение. Что произойдет с объектами file2, file1?
А тот же самый сценарий, только выход из блока кода по какому-то другому исключению?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[17]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, eao197, Вы писали:
E>При выходе из блока кода метод Dispose вызывается у file3. И кидает исключение. Что произойдет с объектами file2, file1?
Нетрудно проверить, что у них будут вызваны методы Dispose:
using System;
class File : IDisposable
{
string name;
public File(string name)
{
this.name = name;
}
public void Dispose()
{
Console.WriteLine(name + " disposed");
if (name == null)
throw new Exception();
}
static void Main()
{
try
{
using (var file1 = new File("file1"))
using (var file2 = new File("file2"))
using (var file3 = new File(null))
{
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
disposed
file2 disposed
file1 disposed
System.Exception: Exception of type 'System.Exception' was thrown.
at File.Dispose()
at File.Main()
Re[18]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, nikov, Вы писали:
E>>При выходе из блока кода метод Dispose вызывается у file3. И кидает исключение. Что произойдет с объектами file2, file1?
N>Нетрудно проверить, что у них будут вызваны методы Dispose:
Это не трудно сделать тому, кто пользуется C#-пом
N>
N> disposed
N>file2 disposed
N>file1 disposed
N>System.Exception: Exception of type 'System.Exception' was thrown.
N> at File.Dispose()
N> at File.Main()
N>
А что же будет, если выход из блока кода происходит по исключению? Какое исключение будет выпущено наружу -- которое из блока кода или из Dispose?
А так же какое исключение будет выпущенно наружу, если file2 и file3 в своем Dispose будут выбрасывать разные исключения.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, eao197, Вы писали:
E>А что же будет, если выход из блока кода происходит по исключению? Какое исключение будет выпущено наружу -- которое из блока кода или из Dispose?
Из Dispose.
E>А так же какое исключение будет выпущенно наружу, если file2 и file3 в своем Dispose будут выбрасывать разные исключения.
То, которое было брошено последним.
Re[20]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, nikov, Вы писали:
N>То, которое было брошено последним.
А чем тогда "последнее" исключение в случае C# лучше, чем "первое" в случае C++?
Или можно получить доступ к текущему исключению и "дописать" туда информацию?
Re[20]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, nikov, Вы писали:
E>>А что же будет, если выход из блока кода происходит по исключению? Какое исключение будет выпущено наружу -- которое из блока кода или из Dispose?
N>Из Dispose.
E>>А так же какое исключение будет выпущенно наружу, если file2 и file3 в своем Dispose будут выбрасывать разные исключения.
N>То, которое было брошено последним.
Ну, собственно, в C# и C++ применены два вполне логичных, но взаимоисключающих подхода к обработке исключений при очистке ресурсов. C++ требует больше работы от разработчика -- задачей разработчика является подавление возможных исключений при очистке ресурсов. C# значительно снижает требования к программисту -- C# сам расставляет за программиста блоки try/catch и сам отвечает за "проглатывания" исключений.
Однако, в любом из подходов потеря исключений происходит.
Вызов terminate в C++ может выглядеть слишком радикальным подходом. Но т.к. в C++ вся ответственность возлагается на программиста, то этот подход вполне в духе C++: не написал try/catch в деструкторе -- получи крах приложения. Что правильно, поскольку выпущенное из деструктора исключение оставляет программу в непонятно каком состоянии. Так что безопаснее рестартовать, чем продолжать работу.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[21]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, VoidEx, Вы писали:
VE>А чем тогда "последнее" исключение в случае C# лучше,
В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку.
VE>чем "первое" в случае C++?
В С++ нет никакого "первого". Из деструкторов C++ не бросают исключений.
Re[22]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, drol, Вы писали:
D>В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку.
Разве с помощью try-catch в деструкторах C++ я не могу получить то же самое?
Re[22]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, drol, Вы писали:
D>В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку.
Покажите, пожалуйста, на этом примере:
using (var file1 = new File( ... ))
using (var file2 = new File( ... ))
{
// ...
}
Здравствуйте, drol, Вы писали:
D>Здравствуйте, VoidEx, Вы писали:
VE>>А чем тогда "последнее" исключение в случае C# лучше,
D>В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку.
На самом деле есть "последний". Не получите вы цепочку, и не надейтесь. Вот вам пример
using System;
namespace Finally
{
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("1");
}
catch (Exception ex)
{
throw new Exception("2", ex);
}
finally
{
// именно в блоке finally зызывается метод Disposethrow new Exception("3");
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
Результат:
System.Exception: 3
at Finally.Program.Main(String[] args) in D:\Projects\Tests\Finally\Program.cs:line 22
Итого имеем потерянную информацию об "1" и "2". Если закомментировать строку throw new Exception("3"); то потери стека не будет и выведется инфа про "1" и "2". Но нас то интересует случай с исключением!
Re[16]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, SE, Вы писали:
C>>Ну ладно. Кинешь исключение из Dispose(). Какой в этом смысл? SE>Да такой же как в выбрасывании любого другого исключения с любом другом месте. Сообщить вызывающему коду об исключительной ситуации.
Ага, и затереть собой предидущее исключение.
C>>Просто единственное ограничение — это не выбрасывать другое исключение за пределы дестркуктора. SE>Т.е. внятно сообщить вызывающему коду о невозможности/ощибке освобождения ресурса не получится? Или я неверно понял?
Неверно. Повторный выброс исключения в C#/Java затирает предидущее исключение. И вместо осмысленного UserPluggedOffUSBDriveException мы получим невнятный IOException при закрытии файла.
Sapienti sat!
Re[16]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, Sinclair, Вы писали:
C>>Ну ладно. Кинешь исключение из Dispose(). Какой в этом смысл? S>Очень простой в этом смысл: сообщаем вызывающему, что детерминистическая финализация не удалась.
И что он с этим будет делать?
S>В отличие от C++, имеем детерминированный способ обработать эту ситуацию. К примеру, попробовать открыть файл на другом устройстве и повторить операцию записи, которая была прервана исключением.
Кто мне мешает сделать то же самое в C++?
Sapienti sat!
Re[23]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, nikov, Вы писали:
D>>В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку.
N>Разве с помощью try-catch в деструкторах C++ я не могу получить то же самое?
Неа.
В С++ (по-факту, стандарт вполне разрешает) нельзя бросать исключения из деструкторов. Связано это с тем, что если исключение бросится из деструктора в процессе раскрутки стека, то (согласно стандарту) последует вызов terminate() и завершение работы программы. Так что внутри деструктора наловить можно много, но вот наружу ничего не вытащить.
Rationale этого решения стандарта, лично я, внятно изложить не могу, хотя идеи есть Вообще было бы интересно почитать чего-нибудь advanced на тему...
*Кстати, попробуйте мыслить деструктор C++ как финалайзер .NET, уважаемый nikov. Я уже показывал в этом топике, что их свойства идентичны. И спецификация C# совершенно неспроста финалайзеры именует деструкторами
Re[24]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, drol, Вы писали:
D>В С++ (по-факту, стандарт вполне разрешает) нельзя бросать исключения из деструкторов. Связано это с тем, что если исключение бросится из деструктора в процессе раскрутки стека, то (согласно стандарту) последует вызов terminate() и завершение работы программы. Так что внутри деструктора наловить можно много, но вот наружу ничего не вытащить.
D>Rationale этого решения стандарта, лично я, внятно изложить не могу
Например как добивать локальный объект, который при выходе из функции в своем деструкторе вдруг кинул исключение? По идее это означает что деструкция не была полностью завершена, объект не был корректно удален, но, тем не менее выход из функции уже его недобитые останки закопал. Что делать? Как его добить в такой ситуации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[23]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, drol, Вы писали:
D>>В C# нет никакого "последнего". Если Вам требуются остальные исключения, то Вы просто обкладываете нужные фрагменты соответствующими try/catch, и можете получить хоть всю цепочку. VE>Покажите, пожалуйста, на этом примере:
VE>
Здравствуйте, Cyberax, Вы писали:
S>>В отличие от C++, имеем детерминированный способ обработать эту ситуацию. К примеру, попробовать открыть файл на другом устройстве и повторить операцию записи, которая была прервана исключением. C>Кто мне мешает сделать то же самое в C++?
Как вызывающий деструкторы код узнает о том, что ж случилось и нужно реагировать, если деструкторы не могут бросать исключения ??? Ну что непонятного-то ???
А больше ничего не мешает. Передвигаете логику очистки ресурса из деструктора в обычную функцию-член, пишите код аналогичный try/finally/using/IDisposable на try/catch'ах и всё. Да, выглядеть будет страшненько, так как try/finally в C++ отсутствует (невозможен?)
*И напоследок. Вы топик вообще читали, уважаемый ??? Я уже раза три разжёвывал тему. Мне обязательно это делать для каждого очередного "чукчи-писателя" зашедшего на огонёк ???
Re[17]: Зачем нужен сборщик мусора? Как жить без деструкторо
Здравствуйте, Cyberax, Вы писали: S>>Очень простой в этом смысл: сообщаем вызывающему, что детерминистическая финализация не удалась. C>И что он с этим будет делать?
Читать постинги целиком.
S>>В отличие от C++, имеем детерминированный способ обработать эту ситуацию. К примеру, попробовать открыть файл на другом устройстве и повторить операцию записи, которая была прервана исключением. C>Кто мне мешает сделать то же самое в C++?
То, что после terminate ничего сделать уже нельзя.
Еще раз поясняю: обычно никакого интереса к повторным исключениям у вызывающего нет. Вот, допустим, код устроен примерно таким образом:
public bool ProcessJob(job j)
{
try
{
using(Stream s = GetStreamForJob(j))
WriteData(s);
return true;
}
catch (Exception e)
{
return false;
}
}
public bool ProcessJobStep(JobQueue q)
{
Job j = q.Dequeue();
j.Attempts++;
if (!ProcessJob(j))
q.Enqueue(); // return to queue for another attempt
}
Совершенно нармальная ситуация. Нам не нужно беспокоиться, что деструктор стрима не сможет сделать flush. Значит, мы можем перейти от небуферизованного стрима к буферизованному. Нам вообще все равно, где возникло исключение: главное, что мы отличаем ситуацию успешной записи от неудачи. В C++ придется делать flush руками, потому что попытка сделать flush в деструкторе приведет к проглоту исключения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.