- 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
Спасибо. Дополнил.