Зачем нужны специальные классы исключений?
почему стандарт C++ потрудился изобрести std::exception
классы? В чем их выгода? Причина, по которой я спрашиваю:
try
{
throw std::string("boom");
}
catch (std::string str)
{
std::cout << str << std::endl;
}
работает нормально. Позже, если мне нужно, я могу просто сделать свои собственные легкие типы "исключений". Так зачем мне беспокоиться о std::exception
?
2 ответов
почему стандарт C++ потрудился изобрести
std::exception
классы? В чем их выгода?
обеспечивает общий и последовательный интерфейс для обработки исключений в стандартной библиотеке. Все исключения, созданные стандартной библиотекой, наследуются от std::exception
.
обратите внимание, что API стандартной библиотеки могут создавать различные исключения, чтобы привести несколько примеров:
std::bad_alloc
std::bad_cast
std::bad_exception
std::bad_typeid
std::logic_error
std::runtime_error
std::bad_weak_ptr | C++11
std::bad_function_call | C++11
std::ios_base::failure | C++11
std::bad_variant_access | C++17
и так далее...std::exception
является базовым классом для всех этих исключений:
предоставление базового класса для всех этих исключений позволяет для обработки нескольких исключений с помощью общего обработчика исключений.
если мне нужно, я могу просто сделать свои собственные легкие типы "исключений". Так зачем мне беспокоиться о std::exception
?
Если вам нужен пользовательский класс исключений, продолжайте и сделайте его. Но!--0--> делает вашу работу проще, потому что она уже предоставляет множество функций, которые должен иметь хороший класс исключений. Он обеспечивает вам легкость выводить от его и overidding необходимые функции(в частности std::exception::what()
) для вашего класса.
Это дает 2 Преимущества std::exception
обработчик,
- можно поймать стандартные исключения библиотеки, а также
- исключения типа пользовательского класса исключений
изображение: http://en.cppreference.com/w/cpp/error/exception
Почему стандарт C++ потрудился изобрести классы std:: exception? В чем их выгода?
имеющих различные виды исключений позволяет поймать конкретные типы ошибок. Получение исключений из общей базы позволяет детализировать улавливание более общих или конкретных ошибок в зависимости от обстоятельств.
В C++ существующий тип система уже на месте, так что стандартизация строк ошибок не требуется, если можно явно создать исключение нужного типа в языке.
std:: exception и его производные классы существуют по двум основным причинам:
стандартная библиотека должна иметь какую-то иерархию исключений для бросьте в исключительных обстоятельствах. Было бы неуместно всегда бросайте std:: string потому что у вас не было бы чистого способа к целевые конкретные виды ошибок.
-
чтобы предоставить расширяемый интерфейс на основе класса для поставщиков библиотеки, чтобы бросить самые основные типы ошибок и обеспечить общий резерв для пользователей. Возможно, вы захотите предоставить больше метаданных ошибок, чем простой что() строка, чтобы человек, поймавший вашу ошибку, мог более разумно оправиться от нее.
в то же время std:: exception как общее основание позволяет общему catchall более менее всеохватывающий, чем ... если пользователь заботится только об этом сообщении об ошибке.
Если все, что вы когда-либо сделать, это распечатать и выйти, то это не имеет значения, но вы можете также использовать std:: runtime_error, который наследует от std:: exception для удобства поймать.
позже, если мне нужно, я могу просто сделать свои собственные легкие типы "исключений". Так зачем мне беспокоиться? std::исключение?
Если вы наследуете от std:: runtime_error и использовать свой собственный тип ошибки, то вы можете ретроактивно добавлять метаданные ошибок без необходимости переписывать блоки catch! Напротив, если вы когда-либо меняли дизайн обработки ошибок, вам придется переписать все ваши std:: string уловы, потому что вы не можете безопасно наследовать от std:: string. Это не перспективный дизайн решение.
Если это не кажется так плохо прямо сейчас, представьте, что ваш код должен стать общим для нескольких проектов в качестве общей библиотеки с различными программистами, работающими над ним. Переход к новой версии вашей библиотеки станет болью.
Это даже не упоминает, что std:: string может создавать свои собственные исключения во время копирования, построения или доступа символов!
веб-сайт Boost имеет некоторые хорошие рекомендации по обработке исключений и классу строительство здесь.
История
Я пишу какой-то сетевой код и использую стороннего поставщика библиотека. На недопустимый ip-адрес, вводимый пользователем это библиотека создает пользовательское исключение nw:: invalid_ip производные от std:: runtime_error. nw:: invalid_ip содержит что() С ОПИСАНИЕМ сообщение об ошибке, но и incorrect_ip() адрес доставленный.
Я также использую std:: vector хранить гнезда, и я использую проверено at () вызов безопасного доступа к индексам. Я знаю, что если я звоните at () на значение за пределами std:: out_of_range бросается.
Я знаю, что другие вещи могут быть брошены, но я не знаю как справиться с ними, или что именно они могут быть.
когда я получаю nw:: invalid_ip ошибка Я открываю модальный файл с вводом поле для пользователя, заполненного недопустимым ip-адресом, чтобы они могли редактировать попробуйте еще раз.
на std:: out_of_range вопросы, я отвечаю, запустив проверку целостности на сокетах и фиксации отношения вектор / сокет, которое упало рассинхронизация.
для любой другой std:: exception проблемы я завершаю программу с помощью журнал ошибок. Наконец-то у меня есть catch(...) какие журналы "неизвестная ошибка!" и прекращает.
было бы трудно надежно сделать это только с std:: string быть брошенным.
вот основной пример нескольких вещей, которые бросаются в разных случаях, чтобы вы могли играть с исключениями ловли.
ExampleExceptions.cpp
#include <vector>
#include <iostream>
#include <functional>
#include <stdexcept>
#include <bitset>
#include <string>
struct Base1 {
virtual ~Base1(){}
};
struct Base2 {
virtual ~Base2(){}
};
class Class1 : public Base1 {};
class Class2 : public Base2 {};
class CustomException : public std::runtime_error {
public:
explicit CustomException(const std::string& what_arg, int errorCode):
std::runtime_error(what_arg),
errorCode(errorCode){
}
int whatErrorCode() const {
return errorCode;
}
private:
int errorCode;
};
void tryWrap(typename std::function<void()> f){
try {
f();
} catch(CustomException &e) {
std::cout << "Custom Exception: " << e.what() << " Error Code: " << e.whatErrorCode() << std::endl;
} catch(std::out_of_range &e) {
std::cout << "Range exception: " << e.what() << std::endl;
} catch(std::bad_cast &e) {
std::cout << "Cast exception: " << e.what() << std::endl;
} catch(std::exception &e) {
std::cout << "General exception: " << e.what() << std::endl;
} catch(...) {
std::cout << "What just happened?" << std::endl;
}
}
int main(){
Class1 a;
Class2 b;
std::vector<Class2> values;
tryWrap([](){
throw CustomException("My exception with an additional error code!", 42);
});
tryWrap([&](){
values.at(10);
});
tryWrap([&](){
Class2 c = dynamic_cast<Class2&>(a);
});
tryWrap([&](){
values.push_back(dynamic_cast<Class2&>(a));
values.at(1);
});
tryWrap([](){
std::bitset<5> mybitset (std::string("01234"));
});
tryWrap([](){
throw 5;
});
}
выход:
Custom Exception: My exception with an additional error code! Error Code: 42
Range exception: vector::_M_range_check
Cast exception: std::bad_cast
Cast exception: std::bad_cast
General exception: bitset::_M_copy_from_ptr
What just happened?