Remkomplekty.ru

IT Новости из мира ПК
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Функция ошибок c

Обработка исключений в C++

Введение

Язык С представляет программисту очень ограниченные возможности обработки исключений, возникших при работе программы. В этом отношении С++ намного развитее С. Здесь у программиста существенно большие возможности по непосредственной обработке исключений. Комитет по разработке стандартов С++ предоставил очень простую, но мощную форму обработки исключений.

Темные дни С

Типичная функция, написанная на С, выглядит примерно так:

Выглядит не очень, не так ли? Вы целиком и полностью зависите от значений, которые возвращают вам функции и для каждой ошибки вам постоянно нужен код, который ее обрабатывает. Если вы, скажем, в функции работаете хотя бы с 10 указателями (рапределяете память, освобождаете ее и т.д.), то наверняка половину кода функции будет занимать код обработки ошибок. Такая же ситуация будет в коде, вызывающем эту функцию, так как здесь также нужно обработать все возвращаемые коды ошибок.

Try-catch-throw

Давайте же разберем основы обработки исключений в С++. Чтобы комфортно работать с исключениями в С++ вам нужно знать лишь три ключевых слова:

  • try (пытаться) — начало блока исключений;
  • catch (поймать) — начало блока, «ловящего» исключение;
  • throw (бросить) — ключевое слово, «создающее» («возбуждающее») исключение.

А теперь пример, демонстрирующий, как применить то, что вы узнали:

Если выполнить этот фрагмент кода, то мы получим следующий результат:

Теперь закоментируйте строку throw 1; и функция выдаст такой результат:

Как видите все очень просто, но если это применить с умом, такой подход покажется вам очень мощным средством обработки ошибок. Catch может «ловить» любой тип данных, так же как и throw может «кинуть» данные любого типа. Т.е. throw AnyClass(); будет правильно работать, так же как и catch (AnyClass &d) <>;.

Как уже было сказано, catch может «ловить» данные любого типа, но вовсе не обязательно при это указывать переменную. Т.е. прекрасно будет работать что-нибудь типа этого:

Так же можно «поймать» и все исключения:

Троеточие в этом случае показывает, что будут пойманы все исключения. При таком подходе нельзя указать имя переменной. В случае, если «кидаются» данные нестандартного типа (экземпляры определенных вами классов, структур и т.д.), лучше «ловить» их по ссылке, иначе вся «кидаемая» переменная будет скопирована в стек вместо того, чтобы просто передать указатель на нее. Если кидаются данные нескольких типов и вы хотите поймать конкретную переменную (вернее, переменную конкретного типа), то можно использовать несколько блоков catch, ловящих «свой» тип данных:

Создание» исключений

Когда возбуждается исключительная ситуация, программа просматривает стек функций до тех пор, пока не находит соответствующий catch. Если оператор catch не найден, STL будет обрабатывать исключение в стандартном обработчике, который делает все менее изящно, чем могли бы сделать вы, показывая какие-то непонятные (для конечного пользователя) сообщения и обычно аварийно завершая программу.

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

Перегрузка глобальных операторов new/delete

А сейчас хотелось бы отправить вас к статье «Как обнаружить утечку памяти». В ней рассказывается, как обнаружить неправильное управление распределением памяти в вашей программе. Вы можете спросить, при чем тут перегрузка операторов? Если перегрузить стандартные new и delete, то открываются широкие возможности по отслеживанию ошибок (причем ошибок часто критических) с помощью исключений. Например:

Это, на первый взгляд, кажется длиннее, чем стандартная проверка в С «а равен NULL?», однако если в программе выделяется десяток динамических переменных, то такой метод оправдывает себя.

Операторы throw без параметров

Итак, мы увидели, как новый метод обработки ошибок удобен и прост. Блок try-catch может содержать вложенные блоки try-catch и если не будет определено соответствующего оператора catch на текущем уровен вложения, исключение будет поймано на более высоком уровне. Единственная вещь, о которой вы должны помнить, — это то, что операторы, следующие за throw, никогда не выполнятся.

Такой метод может применяться в случаях, когда не нужно передавать никаких данных в блок catch.

Приложение

Приведем пример, как все вышеизложенное может быть использовано в конкретном приложении. Преположим, у вас в программе есть класс cMain и экземпляр этого класса Main: class cMain < public: bool Setup(); bool Loop(); // Основной цикл программы void Close(); >; cMain Main;

А в функции main() или WinMain() вы можете использовать этот класс как-нибудь так:

Основной цикл программы может выглядеть примерно так:

Заключение

Метод обработки исключений, приведенный в статье, является удобным и мощным средством, однако только вам решать, использовать его или нет. Одно можно скачать точно — приведенный метод облегчит вам жизнь. Если хотите узнать об исключениях чуть больше, посмотрите публикацию Deep C++ на сервере MSDN.

Обработка ошибок в программах на Си

Хотя C не обеспечивает прямой поддержки обработки ошибок (или обработки исключений), существуют способы, с помощью которых обработка ошибок может быть осуществлена в C. Программист должен в первую очередь предотвращать ошибки и тестировать возвращаемые значения из функций.
Многие вызовы функций C возвращают -1 или NULL в случае ошибки, поэтому быстрое тестирование этих возвращаемых значений легко выполнить, например, с помощью оператора if. Например, в Socket Programming возвращаемое значение функций, таких как socket (), listen () и т. Д., Проверяется на наличие ошибки или нет.

Читать еще:  Ошибка восстановления iphone 5

Пример: обработка ошибок в программировании сокетов

Различные методы обработки ошибок в C

    Глобальная переменная errno: когда в C вызывается функция, переменной с именем errno автоматически присваивается код (значение), который можно использовать для определения типа возникшей ошибки. Это глобальная переменная, указывающая, что ошибка произошла во время любого вызова функции и определена в заголовочном файле errno.h.
    Разные коды (значения) для errno означают разные типы ошибок. Ниже приведен список из нескольких различных значений errno и соответствующего значения:

// Реализация C, чтобы увидеть, как значение errno
// установить в случае любой ошибки в C
#include
#include

// Если файл открыт, который не существует,

// тогда это будет ошибка и соответствующая

// значение errno будет установлено

// открываем файл который

fp = fopen ( «GeeksForGeeks.txt» , «r» );

printf ( » Value of errno: %dn » , errno );

Примечание. Здесь значение errno установлено в 2, что означает — Нет такого файла или каталога. В онлайн-среде IDE может выдаваться ошибка № 13, в которой говорится, что разрешение отклонено.

  • perror () и strerror (): приведенное выше значение errno указывает типы возникших ошибок.
    Если требуется показать описание ошибки, то есть две функции, которые можно использовать для отображения текстового сообщения, связанного с errorno. Функции:
    • perror: отображает строку, которую вы передаете ей, затем двоеточие, пробел, а затем текстовое представление текущего значения errno.
      Синтаксис:
    • strerror (): возвращает указатель на текстовое представление текущего значения errno.
      Синтаксис:

    // Реализация C, чтобы увидеть, как perror () и strerror ()
    // функции используются для печати сообщений об ошибках.
    #include
    #include
    #include

    // Если файл открыт, который не существует,

    // тогда это будет ошибка и соответствующая

    // значение errno будет установлено

    fp = fopen ( » GeeksForGeeks.txt » , «r» );

    // открываем файл который

    printf ( «Value of errno: %dn » , errno );

    printf ( «The error message is : %sn» ,

    perror ( «Message from perror» );

    Выход:
    На личном рабочем столе:

    В онлайн IDE:

    Примечание . Функция perror () отображает переданную ей строку, за которой следует двоеточие и текстовое сообщение с текущим значением errno.

    Состояние выхода: Стандарт C определяет две константы: EXIT_SUCCESS и EXIT_FAILURE, которые могут быть переданы в exit () для указания успешного или неудачного завершения, соответственно. Это макросы, определенные в stdlib.h.

    // C реализация, которая показывает
    // использование EXIT_SUCCESS и EXIT_FAILURE.
    #include
    #include
    #include
    #include

    C++ — Урок 011. Исключения

    Что такое исключение? Это ситуация, которая не предусмотрена стандартным поведением программы. Например, попытка доступа к элементу в классе Vector (который мы разбирали в статье про классы ), который не существует. То есть происходит выход за пределы вектора. В данном случае можно воспользоваться исключениями, чтобы прервать выполнение программы. Это необходимо потому, что

    • Как правило в таких случаях, автор класса Vector не знает, как пользователь захочет использовать его класс, а также не знает в какой программе этот класс будет использоваться.
    • Пользователь класса Vector не может всегда контролировать правильность работы этого класса, поэтому ему нужно сообщить о том, что что-то пошло не так.

    Для разрешения таких ситуация в C++ можно использовать технику исключений.

    Рассмотрим, как написать вызов исключения в случае попытки доступа к элементу по индексу, который не существует в классе Vector.

    Здесь применяется исключение out_of_range. Данное исключение определено в заголовочном файле .

    Оператор throw передаёт контроль обработчику для исключений типа out_of_range в некоторой функции, которая прямо или косвенно вызывает Vector::operator[]() . Для того, чтобы обработать исключения необходимо воспользоваться блоком операторов try catch.

    Инварианты

    Также блоки try catch позволяют производить обработку нескольких различных исключений, что вносит инвариантность в работу механизма исключений C++.

    Например, класс вектор при создании может получить неправильный размер вектора или не найти свободную память для элементов, которые он будет содержать.

    Данный конструктор может выбросить исключение в двух случаях:

    • Если в качестве аргумента size будет передано отрицательное значение
    • Если оператор new не сможет выделить память

    length_error — это стандартный оператор исключений, поскольку библиотека std часто использует данные исключения при своей работе.

    Обработка исключений будет выглядеть следующим образом:

    Также можно выделить свои собственные исключения.

    Виды исключений

    Все исключения стандартной библиотеки наследуются от std::exception.

    На данный момент существуют следующие виды исключений:

    • logic_error
      • invalid_argument
      • domain_error
      • length_error
      • out_of_range
      • future_error (C++11)
    • runtime_error
      • range_error
      • overflow_error
      • underflow_error
      • system_error (C++11)
        • ios_base::failure (начиная с C++11)
    • bad_typeid
    • bad_cast
    • bad_weak_ptr (C++11)
    • bad_function_call (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. Определяет исключение, которое должно быть брошено в случае неправильного аргумента.

    Читать еще:  Ошибка 4013 iphone 7

    Например, на MSDN приведён пример, когда в объект класса bitset из стандартной библиотеки

    В данном примере передаётся неправильная строка, внутри которой имеется символ ‘b’, который будет ошибочным.

    std::domain_error

    Исключение определено в заголовочном файле

    Наследован от std::logic_error. Определяет исключение, которое должно быть брошено в случае если математическая функция не определена для того аргумента, который ей передаётся, например:

    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 применяется к нулевому указателю полиморфного типа.

    std::bad_cast

    Исключение определено в заголовочном файле

    Данное исключение возникает в том случае, когда производится попытка каста объекта в тот тип объекта, который не входит с ним отношения наследования.

    std::bad_weak_ptr

    Исключение определено в заголовочном файле

    std::bad_weak_ptr – тип объекта, генерируемый в качестве исключения конструкторами std::shared_ptr , которые принимают std::weak_ptr в качестве аргумента, когда std::weak_ptr ссылается на уже удаленный объект.

    std::bad_function_call

    Исключение определено в заголовочном файле

    Данное исключение генерируется в том случае, если был вызван метод std::function::operator() объекта std::function , который не получил объекта функции, то есть ему был передан в качестве инициализатора nullptr, например, а объект функции так и не был передан.

    std::bad_alloc

    Исключение определено в заголовочном файле

    Вызывается в том случае, когда не удаётся выделить память.

    std::bad_array_new_length

    Исключение определено в заголовочном файле

    Исключение вызывается в следующих случаях:

    1. Массив имеет отрицательный размер
    2. Общий размер нового массива превысил максимальное значение, определяемое реализацией
    3. Количество элементов инициализации превышает предлагаемое количество инициализирующих элементов

    std::bad_exception

    Исключение определено в заголовочном файле

    std::bad_exception — это тип исключения в C++, которое выполняется в следующих ситуациях:

    1. Если нарушается динамическая спецификация исключений
    2. Если std::exception_ptr хранит копию пойманного исключения, и если конструктор копирования объекта исключения поймал current_exception, тогда генерируется исключение захваченных исключений.

    Рекомендуем хостинг TIMEWEB

    Рекомендуемые статьи по этой тематике

    По статье задано1 вопрос(ов)

    Функция ошибок c

    (C) Dale, 01.02.2011 — 02.02.2011.

    double triangleArea ( double a , double b , double c )
    <
    double p = ( a + b + c ) / 2.0 ;
    double result = sqrt ( p * ( p — a ) * ( p — b ) * ( p — c ) ) ;
    return result ;
    >

    double triangleArea ( double a , double b , double c )
    <
    if ( ( a = ( b + c ) )
    )
    ; // do something?
    double p = ( a + b + c ) / 2.0 ;
    double result = sqrt ( p * ( p — a ) * ( p — b ) * ( p — c ) ) ;
    return result ;
    >

    double triangleArea ( double a , double b , double c )
    <
    if ( ( a = ( b + c ) )
    )
    return — 1.0 ;
    double p = ( a + b + c ) / 2.0 ;
    double result = sqrt ( p * ( p — a ) * ( p — b ) * ( p — c ) ) ;
    return result ;
    >

    double triangleArea ( double a , double b , double c )
    <
    if ( ( a = ( b + c ) )
    )
    exit ( EXIT_FAILURE ) ;
    double p = ( a + b + c ) / 2.0 ;
    double result = sqrt ( p * ( p — a ) * ( p — b ) * ( p — c ) ) ;
    return result ;
    >

    .
    // Защищенный блок
    Try
    <
    .
    потенциально_опасный код
    if (возникла_ошибка)
    Throw(e1); // e1 — код конкретной ошибки
    .
    вызов_потенциально_опасной_функции()
    .
    >
    // Сюда мы попадаем только в случае возникновения ошибки
    Catch(e) // здесь e — код возникшей ошибки
    <
    .
    код_обработки_ошибки
    .
    >
    // Конец защищенного блока
    .

    потенциально_опасная_функция()
    <
    .
    if (возникла_ошибка)
    Throw(e2); // e2 — код конкретной ошибки
    .
    >

    enum ERRORCODE_T
    <
    NEGATIVE_SIDE ,
    BAD_TRIANGLE
    > ;

    extern double triangleArea ( double a , double b , double c ) ;

    #include
    #include
    #include «CException.h»
    #include «ErrorCode.h»
    #include «TriangleArea.h»

    double triangleArea ( double a , double b , double c )
    <
    if ( ( a = ( b + c ) )
    )
    Throw ( BAD_TRIANGLE ) ;

    double p = ( a + b + c ) / 2.0 ;
    double result = sqrt ( p * ( p — a ) * ( p — b ) * ( p — c ) ) ;
    return result ;
    >

    #include
    #include
    #include «TriangleArea.h»
    #include «CException.h»
    #include «ErrorCode.h»

    Читать еще:  Пользовательские типы данных паскаль

    int main ( int argc , char * argv [ ] )
    <
    CEXCEPTION_T e ;
    double a , b , c ;
    a = 10.0 ;
    b = 2.0 ;
    c = 2.0 ;
    printf ( «a=%f b=%f c=%f n » , a , b , c ) ;

    Try
    <
    double area = triangleArea ( a , b , c ) ;
    printf ( «area=%f n » , area ) ;
    >
    Catch ( e )
    <
    switch ( e )
    <
    case NEGATIVE_SIDE :
    printf ( «One of triangle sides is negative. n » ) ;
    break ;

    case BAD_TRIANGLE :
    printf ( «Triangle cannot be made of these sides. n » ) ;
    break ;

    default :
    printf ( «Unknown error: %d n » , e ) ;
    >
    >

    system ( «PAUSE» ) ;
    return 0 ;
    >

    Обработка исключений в C++

    Введение

    Язык С представляет программисту очень ограниченные возможности обработки исключений, возникших при работе программы. В этом отношении С++ намного развитее С. Здесь у программиста существенно большие возможности по непосредственной обработке исключений. Комитет по разработке стандартов С++ предоставил очень простую, но мощную форму обработки исключений.

    Темные дни С

    Типичная функция, написанная на С, выглядит примерно так:

    Выглядит не очень, не так ли? Вы целиком и полностью зависите от значений, которые возвращают вам функции и для каждой ошибки вам постоянно нужен код, который ее обрабатывает. Если вы, скажем, в функции работаете хотя бы с 10 указателями (рапределяете память, освобождаете ее и т.д.), то наверняка половину кода функции будет занимать код обработки ошибок. Такая же ситуация будет в коде, вызывающем эту функцию, так как здесь также нужно обработать все возвращаемые коды ошибок.

    Try-catch-throw

    Давайте же разберем основы обработки исключений в С++. Чтобы комфортно работать с исключениями в С++ вам нужно знать лишь три ключевых слова:

    • try (пытаться) — начало блока исключений;
    • catch (поймать) — начало блока, «ловящего» исключение;
    • throw (бросить) — ключевое слово, «создающее» («возбуждающее») исключение.

    А теперь пример, демонстрирующий, как применить то, что вы узнали:

    Если выполнить этот фрагмент кода, то мы получим следующий результат:

    Теперь закоментируйте строку throw 1; и функция выдаст такой результат:

    Как видите все очень просто, но если это применить с умом, такой подход покажется вам очень мощным средством обработки ошибок. Catch может «ловить» любой тип данных, так же как и throw может «кинуть» данные любого типа. Т.е. throw AnyClass(); будет правильно работать, так же как и catch (AnyClass &d) <>;.

    Как уже было сказано, catch может «ловить» данные любого типа, но вовсе не обязательно при это указывать переменную. Т.е. прекрасно будет работать что-нибудь типа этого:

    Так же можно «поймать» и все исключения:

    Троеточие в этом случае показывает, что будут пойманы все исключения. При таком подходе нельзя указать имя переменной. В случае, если «кидаются» данные нестандартного типа (экземпляры определенных вами классов, структур и т.д.), лучше «ловить» их по ссылке, иначе вся «кидаемая» переменная будет скопирована в стек вместо того, чтобы просто передать указатель на нее. Если кидаются данные нескольких типов и вы хотите поймать конкретную переменную (вернее, переменную конкретного типа), то можно использовать несколько блоков catch, ловящих «свой» тип данных:

    Создание» исключений

    Когда возбуждается исключительная ситуация, программа просматривает стек функций до тех пор, пока не находит соответствующий catch. Если оператор catch не найден, STL будет обрабатывать исключение в стандартном обработчике, который делает все менее изящно, чем могли бы сделать вы, показывая какие-то непонятные (для конечного пользователя) сообщения и обычно аварийно завершая программу.

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

    Перегрузка глобальных операторов new/delete

    А сейчас хотелось бы отправить вас к статье «Как обнаружить утечку памяти». В ней рассказывается, как обнаружить неправильное управление распределением памяти в вашей программе. Вы можете спросить, при чем тут перегрузка операторов? Если перегрузить стандартные new и delete, то открываются широкие возможности по отслеживанию ошибок (причем ошибок часто критических) с помощью исключений. Например:

    Это, на первый взгляд, кажется длиннее, чем стандартная проверка в С «а равен NULL?», однако если в программе выделяется десяток динамических переменных, то такой метод оправдывает себя.

    Операторы throw без параметров

    Итак, мы увидели, как новый метод обработки ошибок удобен и прост. Блок try-catch может содержать вложенные блоки try-catch и если не будет определено соответствующего оператора catch на текущем уровен вложения, исключение будет поймано на более высоком уровне. Единственная вещь, о которой вы должны помнить, — это то, что операторы, следующие за throw, никогда не выполнятся.

    Такой метод может применяться в случаях, когда не нужно передавать никаких данных в блок catch.

    Приложение

    Приведем пример, как все вышеизложенное может быть использовано в конкретном приложении. Преположим, у вас в программе есть класс cMain и экземпляр этого класса Main: class cMain < public: bool Setup(); bool Loop(); // Основной цикл программы void Close(); >; cMain Main;

    А в функции main() или WinMain() вы можете использовать этот класс как-нибудь так:

    Основной цикл программы может выглядеть примерно так:

    Заключение

    Метод обработки исключений, приведенный в статье, является удобным и мощным средством, однако только вам решать, использовать его или нет. Одно можно скачать точно — приведенный метод облегчит вам жизнь. Если хотите узнать об исключениях чуть больше, посмотрите публикацию Deep C++ на сервере MSDN.

  • Ссылка на основную публикацию
    ВсеИнструменты
    Adblock
    detector
    ×
    ×