Подтвердить что ты не робот

Исправить Исключения в С++

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

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
int array[90];
try
{
   ifstream file;
   file.open("somefile.txt");
   if(!file.good())
    throw 56;
}
catch(int e)
{
    cout<<"Error number "<<e<<endl;
}
return 0;
}

Теперь у меня есть два вопроса. Сначала я хотел бы знать, правильно ли я использую Исключения. Во-вторых, (при условии, что первое верно), какова польза от их использования против инструкции If else?

4b9b3361

Ответ 1

"Правильно" - это оценочное суждение, но (в отличие от других классов) существенное преимущество от классов исключений является монолитной иерархией, поэтому я обычно советую бросать что-то из std::exception, а не просто int.

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

Что касается преимуществ против оператора if/else: есть пара. Во-первых, исключения позволяют отделять код, который имеет дело с ошибками, поэтому основная идея и читаемость кода не теряются в лабиринте обработки ошибок. Во-вторых, когда у вас есть несколько уровней кода между броском и ловом исключения, код, который генерирует исключение, может не знать, как его действительно нужно обрабатывать. Например, в вашем коде используется std::cout, чтобы сообщить о проблеме, но в большинстве случаев такой код будет сообщать об ошибках на std::cerr. Вы можете перейти от одного к другому без каких-либо изменений кода, который пытался открыть файл (который может быть глубоким в библиотеке и не имеет понятия, который должен использоваться для этого приложения) и может использоваться в приложении где оба являются неправильными, и MessageBox был предпочтительным).

Ответ 2

Сначала я хотел бы знать, правильно ли я использую Исключения.
Да, хотя обычно вы хотите, чтобы ваши исключения выходили из std:: exception.

Во-вторых, (при условии, что первое верно), в чем преимущество использования их против оператора If else?
Для данного примера ничего. Преимущество исключений возникает, когда у вас есть многие глубокие вложенные функции, например.

#include <stdexcept>
#include <iostream>
#include <string>

void anErrorFunc(const std::string& x)
{
    ifstream file;
    file.open(x);
    if (!file)
        throw std::runtime_error("Could not open file");
}

void someOtherFunction(const std::string& y)
{
    //Do stuff
    anErrorFunc(y);
    //Do other stuff
}

int main()
{
    try {
        someOtherFunction("somefile.txt");
    } catch (std::exception &ex) {
        std::cout << "Ouch! That hurts, because: "
            << ex.what() << "!\n";
    }
}

Обратите внимание, что исключение будет обнаружено в main(), а someOtherFunction не нужно беспокоиться о прохождении через коды возврата отказа.

Ответ 3

Ну, вы правильно используете исключение, потому что в коде нет ничего плохого. Тем не менее, как правило, мы не бросаем примитивные типы (хотя вы можете). Лучше всего бросать объект, который происходит от std:: exception, и даже лучше выкинуть std:: исключение, которое также boost:: exception.

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

Еще одно преимущество обработки исключений заключается в том, что тип исключения может использоваться для передачи типа ошибки, которая произошла. Обычно типы в иерархиях исключений гораздо более значимы, чем те коды ошибок, которые в конечном итоге используются в коде C. Кроме того, вы не можете игнорировать исключение так же легко, как вы можете игнорировать код ошибки; в то время как вы можете игнорировать исключение, это заставит программу умереть от ужасной смерти. В отличие от этого, если функция C возвращает код состояния ошибки, и вы игнорируете ее, можно продолжить выполнение и получить бесшумные результаты... в этом смысле использование исключений гораздо безопаснее, чем использование кодов ошибок.

Вам также может быть интересно узнать о исключениях и обработке ошибок из С++ FAQ Lite.

Ответ 4

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

Исключения, если вы не можете проверить результаты вызова функции другими способами. В этом случае вы можете, поэтому вы не должны использовать исключения.

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

Ответ 5

Синтаксически говоря, ваш код верен. Идиоматично, может быть, не так много - или, по крайней мере, это зависит от контекста. Когда файл не открывается, мы можем сделать свою обработку прямо внутри этого if( !file.good() ), если это совершенно обычное и возможное событие. Например, если пользователь просит открыть файл в текстовом редакторе, то совершенно правдоподобно и распространено, что файл не существует. С другой стороны, если редактор не может найти файл орфографического корпуса, значит, что-то (возможно) ужасно неправильно. Возможно, программа не была установлена, или пользователь перепутал с этим файлом - все возможно.

В С++ мы используем исключения для исключительных случаев. То есть, случаи, которые действительно не должны произойти, и что мы не "принимаем", чтобы произойти. Это в отличие от файла пользователя, который не открывается, или неправильного ввода пользователя, или нет подключения к Интернету: все это примеры совершенно правильных вещей, происходящих, обычных ситуаций, вещей, которые, как мы ожидаем, рано или поздно произойдет в прогоне программы. Они не являются исключительными.

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

Существуют и другие преимущества для исключений по сравнению с условными выражениями: исключения отделяют обработку ошибок от другого кода. Они позволяют связывать произвольные данные и действия с состоянием ошибки. Они позволяют связывать состояния успеха (через return), а также состояние ошибки (через throw). И этот список продолжается...

Технически говоря, а на самом низком уровне исключения - сложный механизм перехода. В дни бабочки люди придумали условный if условный как несколько сложный goto, чтобы повысить выразительность (потому что a goto можно использовать для чего-либо на самом деле) и уменьшить ошибки программиста. Конструкции цикла, такие как цикл C for, также являются, по сути, сложным прыжком со сверкающими и радужными цветами, снова для уменьшения ошибок и повышения выразительности. С++ представил свои новые операторы кастинга по тем же причинам.

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

Ответ 6

Синтаксически то, что вы делаете, правильно. По-разному, как отмечали другие, вы должны выбрасывать что-то из std:: exception.

Что касается второй части вашего вопроса, я хотел бы подробнее рассказать об этом.

Весь смысл исключений - отделить политику от реализации. Как сказал Билли Онел, вы не получаете никакой пользы от использования исключений в рамках той же функции, что оператор if не улучшился бы. Вы должны быть глубоко вложены в вызовы функций, чтобы это имело смысл.

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

Традиционные способы справиться с этим - возвращать коды ошибок - имеют несколько проблем:

  • Он загромождает код с кодом обработки ошибок до того, что фактическая логика запутана.
  • Он полагается на программистов, которые не ленивы и проверяют КАЖДЫЙ возврат кода ошибки, часто безрассудное предположение. (Программисты C, будьте честны здесь: когда вы последний раз проверяли возвращаемое значение printf?)
  • Он добавляет накладные расходы на проверку ошибок и обработку на КАЖДОЙ вызов функции, есть ли ошибка или нет.

Исключения решают эти проблемы (с разной степенью успеха).

  • Исключения решают # 1, только имея код, связанный с исключениями, в точке обнаружения и в момент обработки. Промежуточные функции не загромождают обработку непонятных ошибок, которые они сами не интересуют и не имеют возможности иметь дело.
  • Они решают # 2, заставляя обрабатывать. Вы не можете игнорировать исключение. Вы должны принять меры к ним. (Ленивые программисты все еще могут перехватывать все исключения, а затем игнорировать их, но здесь их искажающая неспособность к программе теперь подсвечивается, чтобы все могли видеть.)
  • Они решают # 3 (когда не наивно реализуются), имея почти нулевые затраты, когда они не используются, хотя часто при очень высокой цене при фактическом использовании.

Это не означает, что исключения - это обработка ошибок. Недостатки:

  • Исключения обычно являются очень дорогостоящими при использовании. Их нужно избегать, несмотря на их преимущества, если производительность имеет первостепенное значение.
  • Исключения иногда приводят к очень непрозрачному коду. Это нелокальные передачи контроля - фактически немного более безопасные версии операторов goto, но через функции. Исключение может передавать управление сотнями слоёв в глубину вашего кода в исходных файлах, даже незначительно связанных с теми, над которыми вы работаете (и, по сути, вполне возможно, даже не доступно для вас). Этот вид "жуткий действия на расстоянии" может сделать код очень трудным для выяснения.
  • "Проверенные исключения" на самом деле могут быть хуже для генерации шума, чем обработка старого стиля if. Видимо, они более подробные, чем операторы if или switch, а тот факт, что вы должны обрабатывать отмеченные исключения для кода даже для компиляции, делает их ответственными за многие ситуации.
  • Из-за их часто высокой стоимости использования, небрежно используя их для обработки ошибок, вы можете сделать ваш код медленным и раздутым.