Я хочу перевести обработку исключений Java в C ++, без использования RAII.
Проблема в основном касается блока finally.
Я нашел статью, в которой используется следующий подход:
«Одна трудность заключается в том, что предложение finally должно выполняться перед каждым выходом из блока try. Существует неожиданное количество потенциальных выходов из общего блока try: нормальный выход, выдача исключения, возврат
оператор, оператор прерывания, оператор продолжения или неспособность поймать исключение. Предложение finally должно выполняться перед каждым из них (если они используются в блоке try или блоке catch). Например, следующий код Java показывает большинство способов выхода из блока try:
try {
switch (x) {
case 0: continue next;
case 1: break out;
case 2: throw new TException();
case 3: return(0);
}
} catch (Error e) {
throw(e);
} finally {
System.out.println("finally");
}
Тогда наше решение состоит в том, чтобы просто дублировать текст блока finally во всех местах, где он должен быть выполнен. Если блок finally имеет значительный размер, это может указывать на то, что программист на Java может захотеть сделать его методом, чтобы минимизировать повторение кода в C ++.
Следующий код C ++ показывает, как блок finally должен быть реплицирован для всех выходов из блока try: «
try
{
switch(x)
{
case 0:
/* finally clause, continue from try block */
java_lang_System::out->println(_j_toString("finally"));
goto next;
case 1:
/* finally clause, break from try block */
java_lang_System::out->println(_j_toString("finally"));
goto out;
case 2:
/* finally clause, throw exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw(new TException());
case 3:
/* finally clause, return from try block */
java_lang_System::out->println(_j_toString("finally"));
return(0);
}
}
catch(java_lang_Error *e)
{
/* finally clause, caught exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw(e);
}
catch(...)
{
/* finally clause, uncaught exception from try block */
java_lang_System::out->println(_j_toString("finally"));
throw;
}
/* finally clause, normal exit from try block */
java_lang_System::out->println(_j_toString("finally"));
Я не понимаю, как использовать его в реальном примере программы. Что такое переменная x в коммутаторе и как ее использовать?
GSL это библиотека, которая поддерживает CppCoreGuidelines. Рекомендации рекомендуют использовать GSL :: наконец за это:
#include <gsl/gsl_util>
int main()
{
std::srand(unsigned(std::time(nullptr)));
auto cleanup = gsl::finally([]{
std::cout << "FINALLY it is my turn." << '\n';
});
try
{
if(std::rand() % 2)
throw std::runtime_error("Woopsie 1");
if(std::rand() % 2)
throw std::logic_error("Woopsie 2");
std::cout << "No woopsies on me" << '\n';
}
catch(std::runtime_error const& e)
{
std::cout << e.what() << '\n';
}
catch(std::logic_error const& e)
{
std::cout << e.what() << '\n';
}
}
Но вы действительно должны перейти к RAII
дизайн для новых классов. Это избавило бы от необходимости использовать объект «наконец».
Замечания: Пожалуйста, получите ваши случайные числа от #include <random>
в реальной жизни.
Это просто пример кода. Смысл в том, что блок Java окончательно вставляется в нескольких точках. Показанный код является просто примером, перечисляя break
, continue
, return
а также throw
что нужно скопировать код блока finally — как окончательный код.
Например:
try {
...
return ...;
...
} finally {
A;
}
станет
try {
...
{ A; }
return ...;
...
{ A; }
} catch (java_lang_Error *e) {
A;
throw e; // If the catch was not there originally
}
На самом деле это то, что происходит в байт-коде Java.
Таким образом, весь код, выходящий из java try-finally, должен копировать код блока finally.