Разница: std:: runtime_error vs std:: exception()

В чем разница между std::runtime_error и std::exception? Какое уместное использование для каждого? Почему они отличаются друг от друга?

Ответ 1

std::exception - это класс, единственная цель которого - служить базовым классом в иерархии исключений. У него нет других применений. Другими словами, концептуально это абстрактный класс (хотя он не определен как абстрактный класс в значении термина С++).

std::runtime_error - более специализированный класс, спускающийся с std::exception, предназначенный для броска в случае различных ошибок времени выполнения. Он имеет двойную цель. Он может быть брошен сам по себе или может служить базовым классом для различных даже более специализированных типов исключений ошибок во время выполнения, таких как std::range_error, std::overflow_error и т.д. Вы можете определить свои собственные классы исключений, спускающиеся с std::runtime_error, а также вы можете определить свои собственные классы исключений, спускающиеся с std::exception.

Так же, как std::runtime_error, стандартная библиотека содержит std::logic_error, также убывающая от std::exception.

Цель этой иерархии - предоставить пользователю возможность использовать всю мощь механизма обработки исключений С++. Поскольку предложение "catch" может ловить полиморфные исключения, пользователь может писать предложения "catch", которые могут захватывать типы исключений из определенного поддерева иерархии исключений. Например, catch (std::runtime_error& e) будет перехватывать все исключения из поддерева std::runtime_error, позволяя всем другим проходить (и летать дальше по стеку вызовов).

P.S. Разработка полезной иерархии классов исключений (которая позволит вам улавливать только типы исключений, которые вас интересуют в каждой точке вашего кода) является нетривиальной задачей. То, что вы видите в стандартной библиотеке С++, - это один из возможных подходов, предложенный авторами этого языка. Как вы видите, они решили разделить все типы исключений на "ошибки времени выполнения" и "логические ошибки" и позволить вам перейти оттуда со своими собственными типами исключений. Есть, конечно, альтернативные способы структурирования этой иерархии, которые могут быть более уместны в вашем дизайне.

Обновление: переносимость Linux и Windows

Как отмечают в комментариях и комментариях Loki Astari и unixman83, конструктор класса exception не принимает никаких аргументов в соответствии со стандартом С++. Microsoft С++ имеет конструктор, который принимает аргументы в классе exception, но это не является стандартным. Класс runtime_error имеет конструктор, принимающий аргументы (char*) на обеих платформах, Windows и Linux. Чтобы быть портативным, лучше использовать runtime_error.

(И помните, только потому, что спецификация вашего проекта говорит, что ваш код не должен запускаться в Linux, это не значит, что он никогда не должен запускаться в Linux.)

Ответ 2

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

std:: runtime_error, с другой стороны, имеет допустимые конструкторы, которые принимают строку как сообщение. Когда what() называется указателем const char, который указывает на строку C, которая имеет ту же строку, что и в конструкторе.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
}