class TryCatch
{
....
public:
void operator () (const char *str); // для типа const char *void operator () (std::exception ex); // для типа std::exception
....
void operator () (); // для оставшихся типов
};
Т.е. блок try конструирует объект-ловушку и для обработки исключений вызываются методы этого объекта.
При этом может случится несколько вызовов, если в процессе исполнения тела блока был вызван error.
В процессе свёртки стека деструкторы классов принудительно "останавливают" исключения.
Т.е. если в деструкторе произошло исключение, то управление передаётся не на конец try блока, а на конец деструктора.
Тем самым снимается проблема исключений в деструкторах.
Здравствуйте, Шахтер, Вы писали:
Ш>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.
Ты можешь написать в комитет и предложить это улучшение. Ш>В отличии от оператора throw, error не прерывает исполнения, а сигнализирует об ошибке.
Вызывай функцию mynamepsace::error и сигнализируй. Ш>Блок try/catch должен быть устроен так
Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?
Здравствуйте, Kernan, Вы писали:
K>Здравствуйте, Шахтер, Вы писали:
K>Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?
В С++ есть проблема обработки кратных ошибок, возникающая при раскрутки стека.
Вот для её удобного решения с поддержкой языка и нужны изменения в механизме исключений.
Здравствуйте, Шахтер, Вы писали:
Ш>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.
1) Зачем запутывать то, что и так запутанно по самое не хочу, ещё дальше?
2) Зачем в деструкторах нужны исключения?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
Ш>>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++. E>1) Зачем запутывать то, что и так запутанно по самое не хочу, ещё дальше?
Не запутывать, а совершенствовать.
E>2) Зачем в деструкторах нужны исключения?
Класс File, например. Исключение сигнализируют об ошибке. Есть масса естественных ситуаций, когда ошибки возникают при завершающих действиях.
class File : NoCopy
{
FileHandle handle;
private:
static ErrorType Open(FileHandle &handle,const char *name);
static ErrorType Close(FileHandle handle);
public:
explicit File(const char *name)
{
if( ErrorType e=Open(handle,name) ) throw e;
}
~File() noexcept(false)
{
if( ErrorType e=Close(handle) ) throw e;
}
};
struct CatchType
{
void operator() (ErrorType e)
{
// печатаем сообщение об ошибке, например
}
};
....
try( CatchType catch_obj )
{
File file1("name1");
File file2("name2");
....
}
// Дошли до конца блока, сработал деструктор file2, выбросил исключение. При этом был вызван оператор () у catch.
// Дальше пошла раскрутка стека. Сработал деструктор file1. Тоже выбросил исключение. Опять был вызван оператор () у catch.
// Второе исключение, однако, передало управление на конец деструктора. Т.е. раскрутка стека продолжилась. В конце концов, управление передано на конец try блока.
Ш>Класс File, например. Исключение сигнализируют об ошибке. Есть масса естественных ситуаций, когда ошибки возникают при завершающих действиях.
Проблема не в том, что ошибки возникают, а в том, что не понятно как их обрабатывать. Отменить-то деструктор мы обычно не можем?
Вот представь себе, что твой File в качестве трёх полей агрегирован в какой-то класс. Мы разрушаем экземпляр этого класса, и во время разрушения второго File получаем исключение "диск полный". Тут, по идее, пользователю надо дать шанс почистить диск и повторить запись. Как делаем?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>В процессе свёртки стека деструкторы классов принудительно "останавливают" исключения. Ш>Т.е. если в деструкторе произошло исключение, то управление передаётся не на конец try блока, а на конец деструктора. Ш>Тем самым снимается проблема исключений в деструкторах.
В качестве эксперимента можно подобное реализовать на базе unwinding_indicator
Здравствуйте, Erop, Вы писали:
E>Вот представь себе, что твой File в качестве трёх полей агрегирован в какой-то класс. Мы разрушаем экземпляр этого класса, и во время разрушения второго File получаем исключение "диск полный". Тут, по идее, пользователю надо дать шанс почистить диск и повторить запись. Как делаем?
Через TLS-стэк обработчиков или например через корутины/потоки.
В принципе вот такой синтаксис реализуется уже сейчас:
{
// near stack root
SPECIAL_TRY
{
write_file();
}
SPECIAL_CATCH(not_enough_space x)
{
if(try_to_free_space(x.size()))
return continue_execution;
else
return throw_exception;
};
}
{
// deep inside stack
raise(not_enough_space{size}); // may throw or continue
// at this point we have enough space
}
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Через TLS-стэк обработчиков или например через корутины/потоки. EP>В принципе вот такой синтаксис реализуется уже сейчас:
Ну это же всё дико сложно работает, и отлаживать трудно и тестами покрывать...
И всё ради чего?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>В С++ есть проблема обработки кратных ошибок, возникающая при раскрутки стека. Ш>Вот для её удобного решения с поддержкой языка и нужны изменения в механизме исключений.
Это, как минимум, нетестируемо... Тебе надо будет покрывать тестами не только все ошибки, но и все их сочетания...
Или ты надеешься обрабатывать ошибки без сайд-эффектов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Проблема не том, как реализовать, а в том, что реализовывать, что бы было не хуже, чем сейчас, а лучше...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>Класс File, например. Исключение сигнализируют об ошибке. Есть масса естественных ситуаций, когда ошибки возникают при завершающих действиях.
Если:
— при закрытии файла (file.close();) можно словить исключение;
— объект file может быть разрушен при раскрутке стука по исключению
... то сделай так чтобы файл не закрывался при разрушении объекта file — все, проблема решина, т.е. вызов file.close(); в деструкторе file по факту ничего уже закрывать не будет и ошибок не произойдет.
Считаем что закрытие файла при разрушении объекта file(раз в этом случае может сгенирироваться исключение) уже есть не совсем нормальное поведение. И если тут происходит еще что то не нормальное ну значит так таму и быть вылетом из приложения по terminate — все логично.
Изночально нужно писать код так чтобы всегда была альтернатива пробрасыванию исключения из деструктора.
А для перекрытия одного исключения другим как раз таки с C++11 у нас появились вложенные исключения.
Здравствуйте, Kernan, Вы писали:
K>Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?
У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)
Здравствуйте, Erop, Вы писали:
EP>>Через TLS-стэк обработчиков или например через корутины/потоки. EP>>В принципе вот такой синтаксис реализуется уже сейчас: E>Ну это же всё дико сложно работает, и отлаживать трудно и тестами покрывать...
Не трудно Есть наборы тестовых состояний среды, и ожидаемые отклики, это всё загоняется в наборы тестовых векторов, и соответственно прогоняется. От метода реализации кстати не особо зависит.
E>И всё ради чего?
Ты же задачу такую поставил, или нет? То есть нужно обработать и исправить ошибку где-то выше по логическому стэку компонентов, там где есть необходимая информация и полномочия, а потом продолжить на исходном низком уровне, так?
Сложность-то она в самой задаче, а не в решении.
Здравствуйте, enji, Вы писали:
E>Здравствуйте, Kernan, Вы писали:
K>>Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?
E>У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Шахтер, Вы писали:
Ш>>В процессе свёртки стека деструкторы классов принудительно "останавливают" исключения. Ш>>Т.е. если в деструкторе произошло исключение, то управление передаётся не на конец try блока, а на конец деструктора. Ш>>Тем самым снимается проблема исключений в деструкторах.
EP>В качестве эксперимента можно подобное реализовать на базе unwinding_indicator
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
Ш>>Класс File, например. Исключение сигнализируют об ошибке. Есть масса естественных ситуаций, когда ошибки возникают при завершающих действиях.
E>Проблема не в том, что ошибки возникают, а в том, что не понятно как их обрабатывать. Отменить-то деструктор мы обычно не можем?
E>Вот представь себе, что твой File в качестве трёх полей агрегирован в какой-то класс. Мы разрушаем экземпляр этого класса, и во время разрушения второго File получаем исключение "диск полный". Тут, по идее, пользователю надо дать шанс почистить диск и повторить запись. Как делаем?
Нет, исключения остаются без возобновления.
А твой случай нужно разруливать не на исключениях, а на продолжениях.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ты же задачу такую поставил, или нет? То есть нужно обработать и исправить ошибку где-то выше по логическому стэку компонентов, там где есть необходимая информация и полномочия, а потом продолжить на исходном низком уровне, так? EP>Сложность-то она в самой задаче, а не в решении.
Ну вот смотри, мы пишем ТРИ файла, флушим, получаем "места нет", и решаем, то надо спросить пользователя что делать. Пользователь говорит: "пиши док на другой диск". И как это случится?
А альтернативный вариант -- у нас всё пишется явно, а не в деструкторе, и вызывающий код всем рулит, пока оно ещё не разрушилось... Второе очевидно проще же?
А как спрашивать вышестоящий код, что делать, через исключения или через колбэки -- не суть.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>А твой случай нужно разруливать не на исключениях, а на продолжениях.
Вот я и спрашиваю, зачем всё так усложнять?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Вообще говоря, если исключения в С++ такие, какие они есть, то значит это кому-то нужно. Не нужно пытаться что-то изменить, всё равно проигнорируют. Например, в Lisp-ах исключения более функциональны и более оптимально реализованы, это появилось задолго до появления С++, и в С++ запросто могли взять исключения по образу и подобию Lisp-овых, но вместо этого нагородили что-то явно более уродливое, непродуманное и неоптимальное. Значит это кому-то нужно.
Здравствуйте, Шахтер, Вы писали:
Ш>В отличии от оператора throw, error не прерывает исполнения, а сигнализирует об ошибке.
Логгер, своя функция и т.п. — сигнализируй не хочу.
Ш>Блок try/catch должен быть устроен так
Опять же, это решается перехватом исключения с подавлением или без подавления этого исключения. Если можем сами — отреагировали на ситуацию и подавили. Если не можем — реагируем на исключение и пробрасываем наверх либо само исключение, либо производное от него (например, оригинальное исключение кладём как дочернее поле в охватывающее исключение, оговоренное контрактом API).
Здравствуйте, enji, Вы писали:
E>Здравствуйте, Kernan, Вы писали:
K>>Я не понял какую проблему ты хочешь решать? Откуда повились эти мысли о error? Изучил новый язык?
E>У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шахтер, Вы писали:
Ш>>А твой случай нужно разруливать не на исключениях, а на продолжениях.
E>Вот я и спрашиваю, зачем всё так усложнять?
это наверное частный случай более общего вопроса — зачем вообще понадобилось вводить исключения.
Здравствуйте, _hum_, Вы писали:
__>это наверное частный случай более общего вопроса — зачем вообще понадобилось вводить исключения.
В данном случае вопрос скорее, зачем вводить продолжения
По исключениям вроде есть удачные практики использования, и там в деструкторах не кидают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, enji, Вы писали:
E>У меня периодически бывают случаи, когда в разных функциях есть одинаковые блоки catch. И счас эта задача нормально не решается — или макры или запоминание и перевыброс текущего исключения (что по идее не быстро)
А почему перевыброс не быстро?
Что там медленного?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.
Незнаю как вам. А мне не хватает функции замера и ограничения ресурсов.
Например вызвать метод c ограниченным временем исполнения,
ограничением на использования стека и динамической памяти.
И чтоб при завершении потока автоматом останавливались его дочерние потоки
и освободдались ресурсы которые они выделяли.
И чтоб это было из коробки.
И много еще чего нехватает. Более того некоторые вещи досих пор удивляют и вызывают недоумение.
Проблемма языков высокого уровня, в моём понимании это упростить написание программ, а не наоборот.
И еще как правило надо не просто решить задачу, а с учетоим каких-то ограничений.
наприер задача отсортировать милиард строк при ограничении по доп. памяти в 16Кб.
или в данном файле запрещено использовать шаблоны
или не использовать макросы
или ни каких fpu только хардкор и битовые операции
или другие соглашения, что б их проверял компилятор.
Но C++ не для этого. Он для вечного изучения и поддержания уже написанных костылей
Главная проблемма что на этих языках пишут люди. У всех людей мозг имеет особенности которые мы получили в результате эволюции
их никто не учитывает при написании языков программирования. В отличии от компьютеров
мозг имеет очень ограниченные возможности и имеет известные недостатки. Пока главным инструментом являлась письменность.
Короче: "Без карандаша с блокнотом, настоящего программиста не получится". Именно из-за особенностей мозга. https://www.youtube.com/watch?v=D_pwT1L7NLU https://www.youtube.com/watch?v=2PD383EtpRw
Здравствуйте, Erop, Вы писали:
EP>>Ты же задачу такую поставил, или нет? То есть нужно обработать и исправить ошибку где-то выше по логическому стэку компонентов, там где есть необходимая информация и полномочия, а потом продолжить на исходном низком уровне, так? EP>>Сложность-то она в самой задаче, а не в решении. E>Ну вот смотри, мы пишем ТРИ файла, флушим, получаем "места нет", и решаем, то надо спросить пользователя что делать. Пользователь говорит: "пиши док на другой диск". И как это случится? E>А альтернативный вариант -- у нас всё пишется явно, а не в деструкторе, и вызывающий код всем рулит, пока оно ещё не разрушилось... Второе очевидно проще же?
А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе Тебе и там и там нужно передать управление в другой контекст, туда где знают как реагировать (например знают как нарисовать GUI диалог), и это основная сложность
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе
1) Деструктор трудно отменить.
2) Если в запросе участвует несколько сущностей, то к моменту вызова деструктора одной из них, остальные могут быть уже разрушены.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе
E>1) Деструктор трудно отменить.
если речь о с++, то там, вроде бы, еще и проблема в том, что
wiki/Обработка исключений
[...]встречается возможность гарантированного завершения блока кода (finally, ensure). Заметным исключением является Си++, где такой конструкции нет. Вместо неё используется автоматический вызов деструкторов объектов.
[...]
Корректная реализация исключений может быть затруднительной в языках с автоматическим вызовом деструкторов. При возникновении исключения в блоке необходимо автоматически вызвать деструкторы объектов, созданных в данном блоке, но только тех, которые не были ещё удалены обычным порядком. Кроме того, требование прерывания текущей операции при возникновении исключения вступает в противоречие с требованием обязательного автоматического удаления в языках с автодеструкторами: если исключение возникнет в деструкторе, то либо компилятор будет вынужден удалить не полностью освобождённый объект, либо объект останется существующим, то есть возникнет утечка памяти. Вследствие этого генерация неперехватываемых исключений в деструкторах в ряде случаев просто запрещается.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, Шахтер, Вы писали:
Ш>>Мне видится, что было бы полезно внести следующие изменения в механизм исключений C++.
_>Незнаю как вам. А мне не хватает функции замера и ограничения ресурсов.
полагаете, что все-таки рост объема обрабатываемых данных опередит рост производительности и емкости устройств?
просто это как бы возврат к уровню си — когда приходится значительное внимание уделять особенностям строения машины, на которой предполагается работа алгоритма...
глянул ваши ссылки на ютьюбе. странный там товарищ, попахивающий "лысенковщиной".
Здравствуйте, Erop, Вы писали:
EP>>А какая разница — в деструкторе инициируется вопрос пользователю или не в деструкторе E>1) Деструктор трудно отменить.
Зачем тебе его отменять?
E>2) Если в запросе участвует несколько сущностей, то к моменту вызова деструктора одной из них, остальные могут быть уже разрушены.
Изменение только в том, что fail будет происходить реже. А вот где он был, и какой механизм использовался — это ортогонально данной дополнительной обработке
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Зачем тебе его отменять?
Ну вот смотри, сценарий.
Я, такой красивый, нажал кнопочку "закрыть окно", окно закрывается, документ флушится на диск, и тут бабам! "МЕСТО ЗАКОНЧИЛОСЬ, ПРИМИТЕ МЕР!".
Я такой смотрю и понимаю, что уронил нечаянно голову на Ctrl+V и так поспал полчасика, и надо бы файло поредактировать мальца, перед тем, как окончательно записывать...
Ну я такой, в филесаве диалоге говорю "отменить", и? Что дальше происходит?
EP>У тебя был код: EP>
EP>Изменение только в том, что fail будет происходить реже. А вот где он был, и какой механизм использовался — это ортогонально данной дополнительной обработке
А если хендлеру надо ПЕРЕМЕСТИТЬ этот файл на другой диск, тока в комплекте ещё с двумя другими. Но CFile одного из этих других уже разрушен?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
немного не по теме но иногда хотелось бы чтобы можно было написать вместо try — retry
то есть бывает некая последовательность действий, которую можно выполнить несколько раз, но в ходе выполнения которой могли бы быть некие проблемы, которые можно починить в catch и перезапустить исходную последовательность
типа
void inner()
{
some_vector.resize(some_value);
}
void outer()
{
try
{
inner();
}catch (bad_alloc &a)
{
free_some_memory();
inner();//если исключение вылезет и отсюда - значицца у нас ничего не получилось :(
}
}
Здравствуйте, ononim, Вы писали:
O>немного не по теме но иногда хотелось бы чтобы можно было написать вместо try — retry O>то есть бывает некая последовательность действий, которую можно выполнить несколько раз, но в ходе выполнения которой могли бы быть некие проблемы, которые можно починить в catch и перезапустить исходную последовательность
моя задумка чтоб код получился попроще для написания и чтения, причем для разных вариантов кода в catch и разных исключений. Вариант с памятью — просто вариант. Могут быть куча других ситуаций типа:
Здравствуйте, ononim, Вы писали:
O>моя задумка чтоб код получился попроще для написания и чтения, причем для разных вариантов кода в catch и разных исключений. Вариант с памятью — просто вариант. Могут быть куча других ситуаций типа:
O>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке...
Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма.
O>>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке... _>Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма.
Вариантов тьма. А вот варинтов таких, чтобы нуб придя на проект в течении секунд 20 врубился что делает код сейчас ровно один:
try
{
work();
}catch
{
repair();
work();
}
Ваши примеры к таким не относятся. Кроме того последний вариант требует "заточки" под себя кода, который он обслуживает, что опять же ухудшает понимабельность и рефакторабельность кода.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ononim, Вы писали:
O>>>И для каждого случая рисовать свою структуру? Тогда уж проще по старинке... _>>Зачем. Как обрабатывать отказы должен задавать вызывающий. И вообще включи воображение. Вариантов тьма. O>Вариантов тьма. А вот варинтов таких, чтобы нуб придя на проект в течении секунд 20 врубился что делает код сейчас ровно один: O>
O>Ваши примеры к таким не относятся. Кроме того последний вариант требует "заточки" под себя кода, который он обслуживает, что опять же ухудшает понимабельность и рефакторабельность кода.
Здравствуйте, _hum_, Вы писали:
__>полагаете, что все-таки рост объема обрабатываемых данных опередит рост производительности и емкости устройств?
От области зависит...
Я вот в области AI работаю, например, таки у нас часто можно разменять время, память и прочую производительность на качество результата. Так что постановка задачи "думаем скока можем себе позволить" вполне жизненная.
Например, если т игрока в шахматы с контролем времени пишешь, то тебе полезно знать скока у тебя осталось времени, а если какой-то рекурсивный переборщик, да ещё и в многопоточном окружении работающий, то часто хочется узнать что-то вроде ответа на вопрос "а сколько её стека есть?"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском