Re[66]: ToString()
От: Павел Кузнецов  
Дата: 29.11.04 12:37
Оценка:
Дарней,

> A> И кстати, не "обрушить", а вызвать terminate(), в котором ты волен произвести необходимые действия перед завершением (послать crash dump разработчику, например).

>
> Программа перестанет работать, не сохранив своих данных, не завершив сеанс работы и т.п.

Все зависит от желания разработчика. Может и сохранить.
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[68]: ToString()
От: Павел Кузнецов  
Дата: 29.11.04 13:13
Оценка: -1
Дарней,

> Я не сомневаюсь, что в случае C++ выброс исключения во время раскрутки стека приводит к неопределенному поведению.


В данном случае, как уже говорил alexeiz, поведение вполне определено. А именно, будет вызвана функция std::terminate().

> Как показал тест — сначала завершаются вызовы Dispose для всех объектов текущего блока, и только затем продолжается раскрутка стека. Происходит это независимо от того, было ли выброшено исключение одним из вызванных методов, или нет <...> Однако, неопределенного поведения здесь все-таки нет.


В результате есть неопределенное состояние программы: освобождены ли все ресурсы, если нет (насколько я понимаю, это именно так), то какие именно "подвисли" и т.п. Плюс, насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[67]: ToString()
От: Дарней Россия  
Дата: 29.11.04 13:16
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Все зависит от желания разработчика. Может и сохранить.


В принципе — можно. Если сначала удостовериться, что terminate вызван по причине исключения при раскрутке стека, а не какой-то другой. Не уверен, что такую проверку легко сделать.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[69]: ToString()
От: Дарней Россия  
Дата: 29.11.04 13:48
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В результате есть неопределенное состояние программы: освобождены ли все ресурсы, если нет (насколько я понимаю, это именно так), то какие именно "подвисли" и т.п. Плюс, насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.


Это и правда не очень хорошо. Но ответственность за вызов Dispose для дочерних объектов все равно лежит на программисте. А он может просто забыть вызвать их вообще — эффект будет тот же
На самом деле, для такого случая (достаточно редкого) можно сделать специальную обработку в виде блока try при каждом вложенном вызове Dispose. Это все равно лучше, чем делать такую обработку всегда, в каждом деструкторе
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[69]: ToString()
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.11.04 17:07
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В результате есть неопределенное состояние программы: освобождены ли все ресурсы, если нет (насколько я понимаю, это именно так), то какие именно "подвисли" и т.п. Плюс, насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.


Ты уже если не знаешь, то старайся спрашивать а не понимать. Обработака диспоз делается по следующему паттерну:
using System;

class Test : IDisposable
{
    public Test(string name) { _name = name; }
    
    string _name;
    
    public void Dispose()
    {
        Console.WriteLine(_name + ".Dispose()");
        throw new Exception("Exception in Dispose... (" + _name + ")");
    }
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            using (Test t1 = new Test("t1"))
            using (Test t2 = new Test("t2"))
            {
                Console.WriteLine("in using...");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}


...
    static void Main(string[] args)
    {
        try
        {
            Test t1 = new Test("t1");
            try
            {
                Test t2 = new Test("t2");
                try
                {
                    Console.WriteLine("in using...");
                }
                finally
                {
                    if (t2 != null)
                        t2.Dispose();
                }
            }
            finally
            {
                if (t1 != null)
                    t1.Dispose();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}


Ну, и соотвествующий выводв:
in using...
t2.Dispose()
t1.Dispose()
Exception in Dispose... (t1)
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[68]: ToString()
От: Павел Кузнецов  
Дата: 29.11.04 18:57
Оценка:
Дарней,

> ПК>Все зависит от желания разработчика. Может и сохранить.


> В принципе — можно. Если сначала удостовериться, что terminate вызван по причине исключения при раскрутке стека, а не какой-то другой. Не уверен, что такую проверку легко сделать.


Я не вижу необходимости именно в такой проверке, т.к. все причины, по которым реализация может вызвать std::terminate, так или иначе связаны с обработкой исключений, и в равной степени фатальны для приложения. Может понадобиться отличать вызовы std::terminate() до инициализации, во время работы программы, и после завершения main(). Но как раз это сделать легко. Теоретически еще может понадобиться отличать вызовы, произошедшие в результате std::unexpected(), но и это делается легко.

15.5.1 The terminate() function

1 In the following situations exception handling must be abandoned for less subtle error handling techniques:
— when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (15.1), calls a user function that exits via an uncaught exception,134)
— when the exception handling mechanism cannot find a handler for a thrown exception (15.3), or
— when the destruction of an object during stack unwinding (15.2) exits using an exception, or
— when construction or destruction of a non-local object with static storage duration exits using an exception (3.6.2), or
— when execution of a function registered with atexit exits using an exception (18.3), or
— when a throw-expression with no operand attempts to rethrow an exception and no exception is being handled (15.1), or
— when unexpected throws an exception which is not allowed by the previously violated exception-specification, and std::bad_exception is not included in that exception-specification (15.5.2), or
— when the implementation’s default unexpected_handler is called (18.6.2.2)
2 In such cases,

void terminate();

is called (18.6.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().

Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[70]: ToString()
От: Павел Кузнецов  
Дата: 29.11.04 19:18
Оценка:
Дарней,

> ПК> В результате есть неопределенное состояние программы: освобождены ли все ресурсы, если нет (насколько я понимаю, это именно так), то какие именно "подвисли" и т.п. Плюс, насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.


> Это и правда не очень хорошо. Но ответственность за вызов Dispose для дочерних объектов все равно лежит на программисте. А он может просто забыть вызвать их вообще — эффект будет тот же


Именно это я и подразумевал под отсутсвием альтернативы деструкторам C++.

> На самом деле, для такого случая (достаточно редкого) можно сделать специальную обработку в виде блока try при каждом вложенном вызове Dispose. Это все равно лучше, чем делать такую обработку всегда, в каждом деструкторе


Там тоже не все так просто: в таком случае информация о неосвобожденных ресурсах будет потеряна. Об аналогичных проблемах в Java была целая статья в журнале Overload, "Handling Exceptions in finally" (Tony Barret-Powell). В on-line, к сожалению, найти не могу...
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[70]: ToString()
От: Павел Кузнецов  
Дата: 29.11.04 19:22
Оценка:
VladD2,

> ПК>В результате есть неопределенное состояние программы: освобождены ли все ресурсы, если нет (насколько я понимаю, это именно так), то какие именно "подвисли" и т.п. Плюс, насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.

>
> Ты уже если не знаешь, то старайся спрашивать а не понимать. Обработака диспоз делается по следующему паттерну:
>
> using System;
>
> class Test : IDisposable
> {
>     public Test(string name) { _name = name; }
>     
>     string _name;
>     
>     public void Dispose()
>     {
>         Console.WriteLine(_name + ".Dispose()");
>         throw new Exception("Exception in Dispose... (" + _name + ")");
>     }
> }
>


Это ответ совсем на другой вопрос. Тенденция, однако...

насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.

т.е. код должен быть немного модифицирован:
class Test : IDisposable
{
     public Test(string name) { _name = name; }

     string _name;

     public void Dispose()
     {
         Console.WriteLine(_name + ".Dispose()");
         throw new Exception("Exception in Dispose... (" + _name + ")");

         // вот здесь должны быть добавлены вызовы других функций, в частности, Dispose других, возможно, содержащихся в Test объектов
     }
}
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[71]: ToString()
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.11.04 22:59
Оценка: -1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Это ответ совсем на другой вопрос. Тенденция, однако...


Как спрашиваешь, так и отвечаем, однако.


ПК>

ПК>насколько я понимаю, не только не будут освобождены ресурсы, в результате освобождения которых было выброшено исключение, но и не будут вызваны остальные функции (в т.ч. и Dispose), которые должны были быть вызваны в "виновном" Dispose, после строки, приведшей к исключению.

ПК>т.е. код должен быть немного модифицирован:
ПК>
ПК>class Test : IDisposable
ПК>{
ПК>     public Test(string name) { _name = name; }

ПК>     string _name;

ПК>     public void Dispose()
ПК>     {
ПК>         Console.WriteLine(_name + ".Dispose()");
ПК>         throw new Exception("Exception in Dispose... (" + _name + ")");

ПК>         // вот здесь должны быть добавлены вызовы других функций, в частности, Dispose других, возможно, содержащихся в Test объектов
ПК>     }
ПК>}
ПК>


Ну, проблемы неграмотного кода никто устронять не собирался. Диспоз вообще по идее не должнен генерировать исключений. И уж если ты работаешь с ресурсами в диспозе, то ставь using или try/catch|finally защищающие код.

Я за все время еще не видел проблем с исключениями в диспозе, а вот с проблемами исключений в конструктерах/деструктерах С++ я видел неоднократно. Уж не знаю, что на это больше влияет, но это факт.

Давай ты опишешь реальный случай, вот его и обсудим.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[71]: ToString()
От: Дарней Россия  
Дата: 30.11.04 05:11
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Именно это я и подразумевал под отсутсвием альтернативы деструкторам C++.


Такова плата за GC.
Можно еще очень долго рассуждать на тему "деструкторы vs Dispose", но на практике Dispose вполне хватает, и никаких особых граблей с ним не возникает.
Если уж искать в языках недостатки, то можно еще много чего вспомнить... например, совершенно уникальный std::auto_ptr с его разрушающим копированием (честное слово — ума не приложу, как вообще комитет мог пропустить такие грабли)
В любом случае — C# меня вполне устраивает, и устраивает больше, чем C++

ПК>Там тоже не все так просто: в таком случае информация о неосвобожденных ресурсах будет потеряна. Об аналогичных проблемах в Java была целая статья в журнале Overload, "Handling Exceptions in finally" (Tony Barret-Powell). В on-line, к сожалению, найти не могу...


Исключения при закрытии ресурсов тема всегда очень щекотливая, независимо от языка
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[68]: ToString()
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.11.04 10:15
Оценка: 15 (1)
Здравствуйте, Дарней, Вы писали:
Д>Параллели между Dispose() и деструкторами С++ очевидны, но это все-таки не одна и та же вещь.
Правильно. Ребята, Dispose — это вообще сахар.
Нужно понимать, что никакого Dispose нет. Есть только try, catch, и finally.
Диспозы вызываются как finally-блок, и никакой неопределенности там нет. Неважно, брошено исключение в рамках Dispose или просто вот так:
try
{
  throw new Exception("1");
} finally
{
  throw new Exception("2");
}


Д>Единственная неопределенность в данном случае — это вопрос о том, какое из исключений будет обрабатываться далее — то, которое изначально привело к раскрутке стека, или одно из тех, которые возникли во время процесса раскрутки. Судя по результатам эксперимента — обрабатываться будет то, которое было выброшено последним.

Д>Это действительно не очень хорошо, т.к. информация о предыдущих исключениях теряется.
Это абсолютно нормально. Вызов Dispose — это часть пользовательского кода! Хочется иметь информацию об исходных исключениях — нет проблем:
using{IDisposable a)
{
  try
    {
    } catch (Exception e)
    {
       // no problem!
    }
}

Д> Однако, неопределенного поведения здесь все-таки нет.
И быть не может. Взаимодействие исключений и пользовательского кода в .Net намного проще, чем в плюсах, и именно из за недетерминистической финализации.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[72]: ToString()
От: Павел Кузнецов  
Дата: 30.11.04 14:53
Оценка:
Дарней,

> ПК> Именно это я и подразумевал под отсутсвием альтернативы деструкторам C++.


> Такова плата за GC.


Не вполне... В C++/CLI введена возможность детерминированного вызова Dispose, например, для автоматических объектов при выходе за пределы блока.

> Если уж искать в языках недостатки, то можно еще много чего вспомнить... например, совершенно уникальный std::auto_ptr с его разрушающим копированием (честное слово — ума не приложу, как вообще комитет мог пропустить такие грабли)


Отчего же... Наоборот, хотят языковую поддержку для move constructors ввести. Это не "грабли", это "фича" — специальный способ указать на передачу владения. Если эта семантика не нужна, следует использовать другие указатели.

> В любом случае — C# меня вполне устраивает, и устраивает больше, чем C++


"Каждый выбирает для себя..."
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[69]: ToString()
От: folk Россия  
Дата: 01.12.04 03:20
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

Понятно, что не стоит допускать ситуаций, когда при необработанном исключении генерируется еще одно. Но раз уж такое случается, то надо с этим как-то жить, и нетовский подход представляется мне более цельным, чем С++овый.

Этот код
A a;
throw "exception";

можно представить так без автоматического вызова конструкторов/деструкторов
A a; // только выделение памяти на стеке
a.ctor();
try {
  throw "exception";
} catch(...) {
  a.dtor();
  throw;
}
a.dtor();

разница только в одном — если деструктор A бросает исключение, то в первом примере получим terminate(), а во втором дальше полетит исключение, выброшенное деструктором.

В этом отличии и заключается нелогичность. Было бы логичнее предъявлять к деструкторам не более жесткие требования, чем к любым функциям, которые могут быть вызваны из catch.
Из catch может быть выброшено как "неожиданное" исключение (например пытаемся выделить память в обработчике и получаем bad_alloc), так и "ожидаемое" (специально выбрасываем новое исключение). Оба эти варианта справедливы и для деструкторов, а значит исключения из деструкторов (при уже активном исключении) должны приводить к тому же — замене старого исключения на новое, а не к terminate().

Самое обидное, что в реализации net-подхода нет никакой net-специфики, на плюсах все это замечательно бы заработало. Имхо, здесь комитетчики приняли неверное решение и не стоит их оправдывать.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[73]: ToString()
От: Дарней Россия  
Дата: 01.12.04 05:09
Оценка: 47 (3)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Отчего же... Наоборот, хотят языковую поддержку для move constructors ввести. Это не "грабли", это "фича" — специальный способ указать на передачу владения. Если эта семантика не нужна, следует использовать другие указатели.


Нужно было просто не делать передачу владения неявной. И не пришлось бы тогда писать вумные книжки с советами наподобие "никогда не создавайте контейнеры из auto_ptr". Мне например кажется просто диким, что operator= изменяет свой правый аргумент.

И все-таки, возвращаясь к деструкторам. Допустим, Dispose бросает исключение. и часть объектов остались незавершенными. Однако завершение остальных объектов будет продолжаться.
С++ в аналогичной ситуации просто "умывает руки", и вообще отказывается освобождать ресурсы проги. Можно конечно попытаться это сделать из terminate, но я сомневаюсь, что из этого может получиться что-то путное. В семействе NT это не будет иметь катастрофических последствий, но то же самое нельзя сказать про ряд других ОС. Плюс к этому, прога может иметь ряд ресурсов, которые не управляются ОС — сеансы работы на сервере приложений, транзакции БД, например. Они конечно будут закрыты через некоторое время по таймауту, но за это время "повисшие" ресурсы могут парализовать работу ряда других юзеров. В результате такое поведение проги может вызвать неопределенное поведение в рамках всей операционной системы юзера, или в рамках корпоративной ИС
С этой точки зрения намного правильнее все-таки попытаться освободить ресурсы, какие получится. И только после этого — может быть, завершить программу.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[70]: ToString()
От: Шахтер Интернет  
Дата: 02.12.04 01:58
Оценка:
Здравствуйте, folk, Вы писали:

F>Здравствуйте, Павел Кузнецов, Вы писали:


F>Понятно, что не стоит допускать ситуаций, когда при необработанном исключении генерируется еще одно. Но раз уж такое случается, то надо с этим как-то жить, и нетовский подход представляется мне более цельным, чем С++овый.


F>Этот код

F>
F>A a;
F>throw "exception";
F>

F>можно представить так без автоматического вызова конструкторов/деструкторов
F>
F>A a; // только выделение памяти на стеке
F>a.ctor();
F>try {
F>  throw "exception";
F>} catch(...) {
F>  a.dtor();
F>  throw;
F>}
F>a.dtor();
F>

F>разница только в одном — если деструктор A бросает исключение, то в первом примере получим terminate(), а во втором дальше полетит исключение, выброшенное деструктором.

F>В этом отличии и заключается нелогичность.


Да нет, это логично -- рапортуем о первичной ошибке. Если в процессе восстановления после ошибки возникла другая ошибка, то это вторичная ошибка, она менее значима. Это ситуация называется double error, и современные прцессоры, например, после этого уходят на перезагрузку.

F>Было бы логичнее предъявлять к деструкторам не более жесткие требования, чем к любым функциям, которые могут быть вызваны из catch.

F>Из catch может быть выброшено как "неожиданное" исключение (например пытаемся выделить память в обработчике и получаем bad_alloc), так и "ожидаемое" (специально выбрасываем новое исключение). Оба эти варианта справедливы и для деструкторов, а значит исключения из деструкторов (при уже активном исключении) должны приводить к тому же — замене старого исключения на новое, а не к terminate().

На самом деле, самым правильным решением было бы реализация каскадирования исключений. Т.е. один объект исключения должен уметь цепляться к другому. А для этого в современный С++ надо всего лишь добавить функцию, возвращающую текущий объект-исключение.

template <class T>
T * GetExceptionObject();


class MyException
 {
  public:
  
   void cascade(MyException);
 };

template <class T>
T * GetExceptionObject();

class Test
 {
  public:
  
   void cleanup() throw(MyException);
 
   ~Test();
 };

Test::~Test()
 {
  try
    {
     cleanup();
    }
  catch(MyException ex)
    {
     if( !uncaught_exception() ) throw;
     
     if( MyException *previous_ex=GetExceptionObject<MyException>() )
       {
        previous_ex->cascade(ex);
       }
     else
       {
        // cannot do anything, ex will be dropped
       }
    }
 }
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[71]: ToString()
От: folk Россия  
Дата: 02.12.04 07:55
Оценка:
Здравствуйте, Шахтер, Вы писали:

F>>Понятно, что не стоит допускать ситуаций, когда при необработанном исключении генерируется еще одно. Но раз уж такое случается, то надо с этим как-то жить, и нетовский подход представляется мне более цельным, чем С++овый.


F>>разница только в одном — если деструктор A бросает исключение, то в первом примере получим terminate(), а во втором дальше полетит исключение, выброшенное деструктором.


F>>В этом отличии и заключается нелогичность.


Ш>Да нет, это логично -- рапортуем о первичной ошибке. Если в процессе восстановления после ошибки возникла другая ошибка, то это вторичная ошибка, она менее значима. Это ситуация называется double error, и современные прцессоры, например, после этого уходят на перезагрузку.


Насчет значимости ошибок. Ты неявно предполагаешь, что вторая является следствием первой, но "вторая ошибка" совсем не значит "вторичная ошибка":
{
  some_resource res1; // деструктор бросит исключение независимо от res2
  some_resource res2; // конструктор бросит исключение
}

Почему же исключение из деструктора res1 вторично? Оно возникает позже, но они скорее равнозначны. Я не могу сказать, которое из них нужнее в общем случае, но пусть будет последнее для согласованности с поведением catch.

Насчет современных процессоров — это просто аналогия.
Мне ближе другая аналогия — если в catch-обработчике, отвечающем за восстановаление после ошибки, возникает ошибка, то дальше обрабатывается именно эта вторая ошибка. Т.е. прецедент в языке уже есть, и было бы логично, чтобы весь код, связанный с восстановлением после ошибок работал по единой схеме. Раз уж нет общего хорошего решения для ситуаций с одновременной генерацией нескольких исключений, то я бы предпочел более простую и понятную схему, а особо важные места обкладывал бы try/catch, завершая приложение вручную, если надо. Здесь был бы очень кстати флаг, показывающий что произошло более одного исключения.

F>>Было бы логичнее предъявлять к деструкторам не более жесткие требования, чем к любым функциям, которые могут быть вызваны из catch.

F>>Из catch может быть выброшено как "неожиданное" исключение (например пытаемся выделить память в обработчике и получаем bad_alloc), так и "ожидаемое" (специально выбрасываем новое исключение). Оба эти варианта справедливы и для деструкторов, а значит исключения из деструкторов (при уже активном исключении) должны приводить к тому же — замене старого исключения на новое, а не к terminate().

Ш>На самом деле, самым правильным решением было бы реализация каскадирования исключений. Т.е. один объект исключения должен уметь цепляться к другому. А для этого в современный С++ надо всего лишь добавить функцию, возвращающую текущий объект-исключение.


[]

Каскадирование — это хорошо, но все равно получается слишком сложный код, чтобы не допустить terminate().
Да и сама возможность прицепить что-либо (например описание контекста возникновения) к текущему исключению — нужная фича. К скожалению к std::exception фиг что прицепишь даже из catch.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[41]: Опять С++ vs С#
От: McSeem2 США http://www.antigrain.com
Дата: 08.12.04 16:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Сборка мусора в среднем занимает около 10 милесекунд с интервалом несколько секунд. А то и реже/быстрее.


Уупс. Целых 10 миллисекунд?! Куда столько?! — этож почти целый кадр. Как говорится в малоизвестном стишке "вы охренели, братья румыны". За 10 миллисекунд я успеваю чисто софтварно отрендерить целую страницу мелкого текста (и Adobe Acrobat, кстати, тоже успевает).
Может все-таки, 10 микросекунд?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[42]: Опять С++ vs С#
От: Павел Кузнецов  
Дата: 08.12.04 19:14
Оценка: +2 -1
McSeem2,

> VD> Сборка мусора в среднем занимает около 10 милесекунд с интервалом несколько секунд. А то и реже/быстрее.


> Уупс. Целых 10 миллисекунд?! Куда столько?! — этож почти целый кадр. Как говорится в малоизвестном стишке "вы охренели, братья румыны". За 10 миллисекунд я успеваю чисто софтварно отрендерить целую страницу мелкого текста (и Adobe Acrobat, кстати, тоже успевает).

> Может все-таки, 10 микросекунд?

Нет, именно миллисекунд. И это не потолок, скорее, характерное время для сбора мусора первого поколения. Сбор объектов поколения 2 может занять значительно дольше.

http://support.microsoft.com/default.aspx?scid=/servicedesks/webcasts/en/wc050102/wct050102.asp

If you look at the actual cost of garbage collecting, that's not collecting that memory that you've allocated, typically a GC of Generation 0 is similar to that of a page fault, so it's fairly cheap. If you look at the actual time that a Generation 0 garbage collection takes, it's typically between 0 and 10 milliseconds, which is fairly short. And then a collection of Generation 1 is typically between 10 and 30 milliseconds. Obviously, the GC of Generation 2 is going to be dependent on what your working set it, but full GCs should not happen that often.


Соответственно, в основном все будет хорошо, но периодически, при запуске уборки поколения 1, кадры будут выпадать, а иногда, при запуске уборки поколения 2, будут паузы, заметные пользвователю. Периодичность этих явлений будет сильно зависить от сценариев работы с памятью. И, в принципе, если реализовать все критичные действия по работе с памятью вручную, как, например, это сделано в Quake, то можно эти эффекты свести к минимуму. Вопрос только в стоимости разработки с ручным управлением памятью на системе, для этого не предназначенной.
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[43]: Опять С++ vs С#
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 08.12.04 19:30
Оценка: :)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Соответственно, в основном все будет хорошо, но периодически, при запуске уборки поколения 1, кадры будут выпадать, а иногда, при запуске уборки поколения 2, будут паузы, заметные пользвователю. Периодичность этих явлений будет сильно зависить от сценариев работы с памятью. И, в принципе, если реализовать все критичные действия по работе с памятью вручную, как, например, это сделано в Quake, то можно эти эффекты свести к минимуму. Вопрос только в стоимости разработки с ручным управлением памятью на системе, для этого не предназначенной.

Выход в создании своего менеджера памяти с использованием валуе типов (массивов байт). Все зависит от задачи и нормально решаемо.
и солнце б утром не вставало, когда бы не было меня
Re[44]: Опять С++ vs С#
От: Павел Кузнецов  
Дата: 08.12.04 19:40
Оценка:
Serginio1,

> ПК> если реализовать все критичные действия по работе с памятью вручную, как, например, это сделано в Quake, то можно эти эффекты свести к минимуму. Вопрос только в стоимости разработки с ручным управлением памятью на системе, для этого не предназначенной.


> Выход в создании своего менеджера памяти с использованием валуе типов (массивов байт). Все зависит от задачи и нормально решаемо.


Гм... В чем здесь противоречие с выделенным?
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.