Пользовательские исключения

Пользовательские исключения позволяют создавать специализированные типы ошибок для конкретных ситуаций в вашем приложении. Они наследуются от стандартных классов исключений и могут содержать дополнительную информацию об ошибке.

Пример пользовательского исключения:
#include <iostream> #include <stdexcept> #include <string> // Простейшее пользовательское исключение class MyException : public std::exception { private: std::string message; public: // Конструктор с возможностью задания сообщения MyException(const std::string& msg) : message(msg) {} // Переопределение метода what() virtual const char* what() const noexcept override { return message.c_str(); } }; void checkValue(int value) { if (value < 0) { throw MyException("Отрицательное значение недопустимо"); } if (value > 100) { throw MyException("Значение превышает максимальный лимит"); } std::cout << "Значение корректно: " << value << std::endl; } int main() { try { checkValue(-5); } catch (const MyException& e) { std::cerr << "Поймано моё исключение: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "Стандартное исключение: " << e.what() << std::endl; } return 0; }
Пояснение:
  • Класс MyException наследуется от std::exception

  • Переопределен метод what() для возврата пользовательского сообщения

  • Конструктор принимает строку с описанием ошибки

  • Исключение бросается с помощью throw и ловится в блоке catch


Иерархия пользовательских исключений:

Можно создавать целые иерархии исключений для разных типов ошибок:

#include <iostream> #include <stdexcept> #include <string> // Базовый класс для исключений файловых операций class FileException : public std::runtime_error { public: FileException(const std::string& msg, const std::string& filename) : std::runtime_error(msg), filename(filename) {} const std::string getFilename() const { return filename; } private: std::string filename; }; // Исключение для ошибок открытия файла class FileOpenException : public FileException { public: FileOpenException(const std::string& filename) : FileException("Не удалось открыть файл", filename) {} }; // Исключение для ошибок чтения файла class FileReadException : public FileException { public: FileReadException(const std::string& filename, int line) : FileException("Ошибка чтения файла", filename), line(line) {} const int getLine() const { return line; } private: int line; }; void processFile(const std::string& filename) { // Имитация ошибки if (filename.empty()) { throw FileOpenException(filename); } if (filename == "corrupted.dat") { throw FileReadException(filename, 42); } std::cout << "Файл " << filename << " успешно обработан" << std::endl; } int main() { try { processFile("corrupted.dat"); } catch (const FileReadException& e) { std::cerr << "Ошибка чтения: " << e.what() << "\nФайл: " << e.getFilename() << "\nСтрока: " << e.getLine() << std::endl; } catch (const FileOpenException& e) { std::cerr << "Ошибка открытия: " << e.what() << "\nФайл: " << e.getFilename() << std::endl; } catch (const FileException& e) { std::cerr << "Файловая ошибка: " << e.what() << "\nФайл: " << e.getFilename() << std::endl; } return 0; }
Пояснение:
  • Создана иерархия: FileExceptionFileOpenException и FileReadException

  • Каждый класс добавляет свою специфическую информацию (имя файла, номер строки)

  • Обработчики расположены от наиболее специфичных к наиболее общим


Пользовательские исключения с дополнительными данными:

Можно добавлять любые дополнительные данные в исключения:

#include <iostream> #include <stdexcept> #include <string> #include <ctime> // Исключение с временной меткой class TimestampedException : public std::runtime_error { public: TimestampedException(const std::string& msg) : std::runtime_error(msg), timestamp(std::time(nullptr)) {} std::string getTimestamp() const { char buf[80]; std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(×tamp)); return buf; } private: std::time_t timestamp; }; // Исключение для ошибок в финансовых операциях class FinancialTransactionException : public TimestampedException { public: FinancialTransactionException(const std::string& msg, double amount, const std::string& account) : TimestampedException(msg), amount(amount), account(account) {} const double getAmount() const { return amount; } const std::string& getAccount() const { return account; } private: double amount; std::string account; }; void processTransaction(double amount, const std::string& account) { if (amount <= 0) { throw FinancialTransactionException("Некорректная сумма транзакции", amount, account); } if (account.empty()) { throw FinancialTransactionException("Не указан счет", amount, account); } std::cout << "Транзакция на сумму " << amount << " по счету " << account << " выполнена" << std::endl; } int main() { try { processTransaction(-100.0, "ACC123456"); } catch (const FinancialTransactionException& e) { std::cerr << "Ошибка транзакции [" << e.getTimestamp() << "]:\n" << e.what() << "\n" << "Сумма: " << e.getAmount() << "\n" << "Счет: " << e.getAccount() << std::endl; } return 0; }
Пояснение:
  • TimestampedException добавляет временную метку момента создания исключения

  • FinancialTransactionException добавляет сумму и номер счета

  • Данные доступны через методы getter'ы при обработке исключения


Исключения с кодом ошибки:

Часто полезно включать код ошибки в исключение:

#include <iostream> #include <stdexcept> #include <string> #include <map> class ErrorCodeException : public std::runtime_error { public: ErrorCodeException(int code, const std::string& msg) : std::runtime_error(msg), errorCode(code) {} int getErrorCode() const { return errorCode; } static std::string getErrorDescription(int code) { static const std::map<int, std::string> descriptions = { {100, "Недостаточно прав"}, {101, "Ресурс не найден"}, {102, "Неверный формат данных"}, {200, "Ошибка соединения"}, {201, "Таймаут соединения"} }; auto it = descriptions.find(code); return it != descriptions.end() ? it->second : "Неизвестная ошибка"; } private: int errorCode; }; void checkAccess(bool isAdmin) { if (!isAdmin) { throw ErrorCodeException(100, "Требуются права администратора"); } std::cout << "Доступ разрешен" << std::endl; } int main() { try { checkAccess(false); } catch (const ErrorCodeException& e) { std::cerr << "Ошибка " << e.getErrorCode() << ": " << e.what() << "\n" << "Описание: " << ErrorCodeException::getErrorDescription(e.getErrorCode()) << std::endl; } return 0; }
Пояснение:
  • Исключение содержит числовой код ошибки

  • Статический метод getErrorDescription предоставляет описание по коду

  • Коды ошибок можно использовать для локализации или логирования


Пользовательские исключения позволяют:

  • Создавать специализированные типы ошибок для вашего приложения

  • Передавать дополнительную информацию об ошибке

  • Строить сложные иерархии обработки ошибок

  • Делать код более читаемым и поддерживаемым


Комментарии

Добавить комментарий

Чтобы оставить комменатрий необходимо Авторизоваться

Содежание
1. Введение в язык C++ 2. Установка компилятора 3. Установка среды разработки (IDE) 4. Структура программы и компиляция 5. Переменные, константы и типы данных 6. Операторы и выражения 7. Ввод и вывод в консоли 8. Условные операторы 9. Логические выражения 10. Циклы 11. Массивы 12. Динамические массивы 13. Указатели в С++ 14. Ссылки в C++ 15. Функции 16. Рекурсия 17. Callback-функции 18. Динамическое выделение памяти 19. Утечки памяти и как их избежать 20. Умные указатели в С++ 21. Парадигмы программирования 22. Структуры (struct) 23. Классы и объекты в C++ 24. Инкапсуляция 25. Наследование 26. Полиморфизм 27. Абстрактные классы 28. Списки инициализации 29. Перегрузка операторов 30. Обработка исключений 31. Пользовательские исключения 32. Шаблонные функции в C++ 33. Шаблонные классы в C++ 34. STL и использование стандартных шаблонов 35. Аллокаторы и пользовательские распределители памяти 36. Работа с файлами