- 1. Незмінний
- 2. Види винятків
- 3. std::logic_error
- 4. std::invalid_argument
- 5. std::domain_error
- 6. std::length_error
- 7. std::out_of_range
- 8. std::future_error
- 9. std::runtime_error
- 10. std::range_error
- 11. std::overflow_error
- 12. std::underflow_error
- 13. std::system_error
- 14. std::ios_base::failure
- 15. std::bad_typeid
- 16. std::bad_cast
- 17. std::bad_weak_ptr
- 18. std::bad_function_call
- 19. std::bad_alloc
- 20. std::bad_array_new_length
- 21. std::bad_exception
Що таке виняток? Це ситуація, яка не передбачена стандартною поведінкою програми. Наприклад, спроба доступу до елемента у класі Vector (який ми розбирали у статті про класи ), який не існує. Тобто відбувається вихід межі вектора. У цьому випадку можна скористатися винятками, щоб перервати виконання програми. Це необхідно тому, що
- Як правило в таких випадках, автор класу Vector не знає, як користувач захоче використовувати його клас, а також не знає, в якій програмі цей клас буде використовуватись.
- Користувач класу Vector не може завжди контролювати правильність роботи цього класу, тому йому потрібно повідомити, що щось пішло не так.
Для вирішення таких ситуацій у C++ можна використовувати техніку винятків.
Розглянемо, як написати виклик виключення у разі спроби доступу до елемента за індексом, який немає у класі Vector.
- double& Vector::operator[](int i)
- {
- if (i<0 || size()<=i) throw out_of_range{"Vector::operator[]"};
- return elem[i];
- }
Тут застосовується виняток
out_of_range.
Цей виняток визначено у заголовному файлі
Оператор throw передає контроль обробнику для винятків типу out_of_range у деякій функції, яка прямо чи опосередковано викликає Vector::operator . Для того, щоб обробити винятки, необхідно скористатися блоком операторів try catch.
- void f(Vector& v)
- {
- // ...
- try { // блок обработки функции с исключением
- v[v.size()] = 7; // попытка доступа к элементу за пределами вектора
- }
- catch (out_of_range) { // ловим ошибку out_of_range
- // ... обработки ошибки out_of_range ...
- }
- // ...
- }
Незмінний
Також блоки try catch дозволяють проводити обробку декількох різних винятків, що вносить інваріантність в роботу механізму винятків C++.
Наприклад, клас вектор при створенні може отримати неправильний розмір вектора або знайти вільну пам'ять для елементів, які він міститиме.
- Vector::Vector(int s)
- {
- if (s < 0) throw length_error{};
- elem = new double[s];
- sz = s;
- }
Цей конструктор може викинути виняток у двох випадках:
- Якщо як аргумент size буде передано негативне значення
- Якщо оператор new не зможе виділити пам'ять
length_error - це стандартний оператор винятків, оскільки бібліотека std часто використовує дані винятки у своїй роботі.
Обробка винятків буде виглядати так:
- void test()
- {
- try {
- Vector v(−27);
- }
- catch (std::length_error) {
- // обработка отрицательного размера вектора
- }
- catch (std::bad_alloc) {
- // обработка ошибки выделения памяти
- }
- }
Також можна виділити власні винятки.
Види винятків
Усі винятки стандартної бібліотеки успадковуються від std::exception.
На даний момент існують такі види винятків:
- логічна_помилка
- недійсний_аргумент
- помилка домену
- довжина_помилка
- поза_діапазоном
- future_error (C++11)
- Помилка виконання
- помилка_діапазону
- помилка переповнення
- underflow_error
- системна_помилка (C++11)
- ios_base::failure (починаючи з C++11)
- bad_typeid
- bad_cast
- bad_weak_ptr (C++11)
- поганий_виклик_функції (C++11)
- bad_alloc
- bad_array_new_length (C++11)
- bad_exception
- ios_base::failure (до C++11)
std::logic_error
Виняток визначено у заголовному файлі
Визначає тип об'єкта, який буде кинутий як виняток. Він повідомляє про помилки, які є наслідком неправильної логіки в рамках програми, такі як порушення логічної передумови або клас інваріантів, яких можна запобігти.
Цей клас використовується як основа для помилок, які можна визначити лише під час виконання програми.
std::invalid_argument
Виняток визначено у заголовному файлі
Спадкоємий від std::logic_error. Визначає виняток, який має бути кинуто у разі неправильного аргументу.
Наприклад, на MSDN наведено приклад, коли в об'єкт класу bitset зі стандартної бібліотеки
- // invalid_arg.cpp
- // compile with: /EHsc /GR
- #include <bitset>
- #include <iostream>
- using namespace std;
- int main( )
- {
- try
- {
- bitset< 32 > bitset( string( "11001010101100001b100101010110000") );
- }
- catch ( exception &e )
- {
- cerr << "Caught " << e.what( ) << endl;
- cerr << "Type " << typeid( e ).name( ) << endl;
- };
- }
- \* Output:
- Caught invalid bitset<N> char
- Type class std::invalid_argument
- *\
У цьому прикладі передається неправильний рядок, усередині якого є символ 'b', який буде помилковим.
std::domain_error
Виняток визначено у заголовному файлі
Спадкоємий від std::logic_error. Визначає виняток, який має бути кинуто, якщо математична функція не визначена для того аргументу, який їй передається, наприклад:
- std::sqrt(-1)
std::length_error
Виняток визначено у заголовному файлі
Спадкоємий від std::logic_error. Визначає виняток, який має бути броше у тому випадку, коли здійснюється спроба реалізації перевищення допустимих меж для об'єкта. Як було показано для розміру вектора на початку статті.
std::out_of_range
Виняток визначено у заголовному файлі
Спадкоємий від std::logic_error. Визначає виняток, який має бути кинуто у разі, коли відбувається вихід межі допустимого діапазону значень об'єкта. Як це було показано для діапазону значень вітру на початку статті.
std::future_error
Виняток визначено у заголовному файлі
Спадкоємий від std::logic_error. Цей виняток може бути викинутий у тому випадку, якщо не вдалося виконати функцію, яка працює в асинхронному режимі та залежить від бібліотеки потоків. Це виняток несе код помилки, сумісний з std::error_code .
std::runtime_error
Виняток визначено у заголовному файлі
Є базовим винятком для винятків, які можуть бути легко передбачені і мають бути кинуті під час виконання програми.
std::range_error
Виняток визначено у заголовному файлі
Виняток використовується при помилках при обчисленні значень з плаваючою комою, коли комп'ютер не може обробити значення, оскільки воно або занадто великим, або занадто маленьким. Якщо значення є значенням інтегрального типу, то повинні використовуватися винятки underflow_error або overflow_error .
std::overflow_error
Виняток визначено у заголовному файлі
Виняток використовується при помилках при обчисленні значень з плаваючою комою інтегрального типу, коли число має дуже велике позитивне значення, позитивну нескінченність, коли відбувається втрата точності, тобто. результат настільки великий, що може бути представлений числом форматі IEEE754.
std::underflow_error
Виняток визначено у заголовному файлі
Виняток використовується при помилках при обчисленні значень з плаваючою комою інтегрального типу, коли відбувається втрата точності, тобто. результат настільки малий, що може бути представлений числом форматі IEEE754.
std::system_error
Виняток визначено у заголовному файлі
std::system_error - це тип виключення, який викликається різними функціями стандартної бібліотеки (як правило, функції, які взаємодіють з операційною системою, наприклад, конструктор std::thread ), при цьому виняток має відповідний * std::error_code * .
std::ios_base::failure
Виняток визначено у заголовному файлі
Відповідає за винятки, які викидаються при помилках функцій виводу.
std::bad_typeid
Виняток визначено у заголовному файлі
Виняток цього виникає, коли оператор typeid застосовується до нульовому покажчику поліморфного типу.
- #include <iostream>
- #include <typeinfo>
- struct S { // Тип должен быть полиморфным
- virtual void f();
- };
- int main()
- {
- S* p = nullptr;
- try {
- std::cout << typeid(*p).name() << '\n';
- } catch(const std::bad_typeid& e) {
- std::cout << e.what() << '\n';
- }
- }
std::bad_cast
Виняток визначено у заголовному файлі
Даний виняток виникає у тому випадку, коли робиться спроба каста об'єкта в той тип об'єкта, який не входить із ним відношення спадкування.
- #include <iostream>
- #include <typeinfo>
- struct Foo { virtual ~Foo() {} };
- struct Bar { virtual ~Bar() {} };
- int main()
- {
- Bar b;
- try {
- Foo& f = dynamic_cast<Foo&>(b);
- } catch(const std::bad_cast& e)
- {
- std::cout << e.what() << '\n';
- }
- }
std::bad_weak_ptr
Виняток визначено у заголовному файлі
std::bad_weak_ptr – тип об'єкта, що генерується як виняток конструкторами std::shared_ptr , які приймають std::weak_ptr як аргумент, коли std::weak_ptr посилається вже віддалений об'єкт.
- #include <memory>
- #include <iostream>
- int main()
- {
- std::shared_ptr<int> p1(new int(42));
- std::weak_ptr<int> wp(p1);
- p1.reset();
- try {
- std::shared_ptr<int> p2(wp);
- } catch(const std::bad_weak_ptr& e) {
- std::cout << e.what() << '\n';
- }
- }
std::bad_function_call
Виняток визначено у заголовному файлі
Даний виняток генерується в тому випадку, якщо був викликаний метод std::function::operator() об'єкта std::function , який не отримав об'єкта функції, тобто йому був переданий як ініціалізатор nullptr, наприклад, а об'єкт функції так і не було передано.
- #include <iostream>
- #include <functional>
- int main()
- {
- std::function<int()> f = nullptr;
- try {
- f();
- } catch(const std::bad_function_call& e) {
- std::cout << e.what() << '\n';
- }
- }
std::bad_alloc
Виняток визначено у заголовному файлі
Викликається у разі, коли вдається виділити пам'ять.
std::bad_array_new_length
Виняток визначено у заголовному файлі
Виняток викликається у таких випадках:
- Масив має негативний розмір
- Загальний розмір нового масиву перевищив максимальне значення, що визначається реалізацією
- Кількість елементів ініціалізації перевищує пропоновану кількість елементів, що ініціалізують
- #include <iostream>
- #include <new>
- #include <climits>
- int main()
- {
- int negative = -1;
- int small = 1;
- int large = INT_MAX;
- try {
- new int[negative]; // negative size
- new int[small]{1,2,3}; // too many initializers
- new int[large][1000000]; // too large
- } catch(const std::bad_array_new_length &e) {
- std::cout << e.what() << '\n';
- }
- }
std::bad_exception
Виняток визначено у заголовному файлі
std::bad_exception - це тип винятку в C++, який виконується у таких ситуаціях:
- Якщо порушується динамічна специфікація винятків
- Якщо std::exception_ptr зберігає копію спійманого виключення, і якщо конструктор копіювання об'єкта виключення упіймав current_exception, тоді генерується виняток захоплених винятків.
- #include <iostream>
- #include <exception>
- #include <stdexcept>
- void my_unexp() { throw; }
- void test() throw(std::bad_exception)
- {
- throw std::runtime_error("test");
- }
- int main()
- {
- std::set_unexpected(my_unexp);
- try {
- test();
- } catch(const std::bad_exception& e)
- {
- std::cerr << "Caught " << e.what() << '\n';
- }
- }
std::underflow_error - это не "число имеет слишком большое отрицательное значение", а потеря точности при вычислениях, т.е. результат настолько мал, что не может быть представлен числом в формате IEEE754
Спасибо. Дополнил.