Могу ли я иметь вложенные блоки try-catch в С++?

Могу ли я иметь вложенные блоки try-catch? Например:


void f()
{
    try
    {
        //Some code 
        try
        {
             //Some code 
        }
        catch(ExceptionA a)
        {
            //Some specific exception handling
        }
        //Some code
    }
    catch(...)
    {
        //Some exception handling
    }
}//f

Ответы

Ответ 1

Да, совершенно законный.

Хотя было бы лучше перенести внутренние на другой метод, чтобы он выглядел чище, а ваш метод меньше

Ответ 2

Как уже было сказано, это возможно, но вы должны увидеть в этом схему "проваливания". Если в первом блоке try-catch блокируется ваше исключение, он не будет попадать во внешний блокирующий блок. Однако, если он не попадает во внутренний блокирующий блок, он попытается найти соответствующий обработчик исключений во внешнем блоке catch.

Вы также можете явно добавить исключение к следующему обработчику исключений, используя throw; в своем внутреннем обработчике исключений.

Например, этот код:

try
{
    try
    {
        throw std::runtime_error("Test");
    }
    catch (std::runtime_error& e)
    {
        std::cerr << "Inner Exception-Handler: " << e.what() << std::endl;
        throw;
    }
}
catch (std::exception& e)
{
    std::cerr << "Outer Exception-Handler: " << e.what() << std::endl;
}

приведет к:

Inner Exception-Handler: Test
Outer Exception-Handler: Test

Это работает, потому что std:: runtime_error получен из std:: exception. Следует также отметить, что в таком тривиальном примере также можно просто написать блоки catch друг за другом, но если вы хотите выполнить другой код после первого блока catch, вам придется их вложить.

Ответ 3

Да, это законно. Как сказал ouster, один из способов борьбы с ним состоит в том, чтобы поместить внутренний блок try-catch в свою собственную функцию и вызвать эту функцию из вашего внешнего блока try-catch.

Другой способ справиться с этим - с несколькими блоками catch.

void f()
{
    try
    {
        //Some code that throws ExceptionA
        //Some code that throws ExceptionB
    }
    catch(ExceptionA ea)
    {
        //Some exception handling
    }
    catch(ExceptionB eb)
    {
        //Some exception handling
    }
}//f

Вещь, которую нужно соблюдать, - это специфика типов исключений в ваших блоках catch. Если ExceptionB расширяет ExceptionA в приведенном выше примере, тогда блок ExceptionB никогда не будет вызван, потому что любой ExceptionB, который будет выброшен, будет обработан блоком ExceptionA. Вы должны заказать блоки catch в наиболее специфическом для наименее определенного порядка при работе с иерархиями классов исключений.

Ответ 4

Да, вы можете.

Ответ 5

Его законный, но его не все, что полезно, если вы не выбрасываете исключение из своего внутреннего catch(). Например, вы можете поймать исключение на системном уровне, но бросить свой собственный объект исключения для ясности кода.