Evgenii Legotckoi
Evgenii Legotckoi15 жовтня 2017 р. 17:31

C++ - Підручник 011. Винятки

Що таке виняток? Це ситуація, яка не передбачена стандартною поведінкою програми. Наприклад, спроба доступу до елемента у класі 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

Виняток визначено у заголовному файлі

Виняток викликається у таких випадках:

  1. Масив має негативний розмір
  2. Загальний розмір нового масиву перевищив максимальне значення, що визначається реалізацією
  3. Кількість елементів ініціалізації перевищує пропоновану кількість елементів, що ініціалізують
#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++, який виконується у таких ситуаціях:

  1. Якщо порушується динамічна специфікація винятків
  2. Якщо 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';
    }
}
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

P
  • 15 жовтня 2017 р. 23:00

std::underflow_error - это не "число имеет слишком большое отрицательное значение", а потеря точности при вычислениях, т.е. результат настолько мал, что не может быть представлен числом в формате IEEE754

Evgenii Legotckoi
  • 16 жовтня 2017 р. 02:46

Спасибо. Дополнил.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
Дмитрий

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60бали,
  • Рейтинг балів-1
Дмитрий

C++ - Тест 003. Условия и циклы

  • Результат:92бали,
  • Рейтинг балів8
d
  • dsfs
  • 26 квітня 2024 р. 04:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
k
kmssr08 лютого 2024 р. 18:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 01:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 10:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 08:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 грудня 2023 р. 21:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
George1307 травня 2024 р. 00:27
добавить qlineseries в функции в функции: "GPlotter::addSeries(QString title, QVector &arr)" я вызываю метод setChart(...), я в конструктор передал адрес на QChartView элемент
BlinCT
BlinCT05 травня 2024 р. 05:46
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
PS
Peter Son03 травня 2024 р. 17:57
Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
Evgenii Legotckoi
Evgenii Legotckoi02 травня 2024 р. 14:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 квітня 2024 р. 04:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

Слідкуйте за нами в соціальних мережах