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-овых, но вместо этого нагородили что-то явно более уродливое, непродуманное и неоптимальное. Значит это кому-то нужно.