Исключения в C ++ - плохо ли бросать c-строку как исключение? - PullRequest
33 голосов
/ 06 июня 2011

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

try {
    // code
    if (some error) {
        throw "Description of error.";
    }
}
catch (char* errorMessage) {
    cerr << errorMessage << endl << "Fatal error";
}

Что-то не так с использованием массива char в качестве исключения?

РЕДАКТИРОВАТЬ: это будет лучший способ пойти?

const char errorMessage[] = "Description of error";

try {
    // code
    if (some error) {
        throw errorMessage;
    }
}
catch (char* errorMessage) {
   cerr << errorMessage << endl << "Fatal error";
}

Ответы [ 7 ]

48 голосов
/ 06 июня 2011

Гораздо лучше бросить объект стандартного исключения. В общем, лучшая практика - генерировать что-то, полученное из std::exception, так что если в какой-то ситуации это приведет к завершению вашей программы, у реализации будет больше шансов распечатать полезную диагностику.

Поскольку это не сложно, я бы никогда не рекомендовал бросать необработанный строковый литерал.

#include <stdexcept>

void someFunction()
{
    try {
        // code
        if (some error) {
            throw std::runtime_error( "Description of error." );
        }
    }
    catch (const std::exception& ex) {
        std::cerr << ex.what() << "\nFatal error" << std::endl;
    }
}
10 голосов
/ 06 июня 2011

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

Учитывая неизвестный клиентский код, который перехватывает const char*, программисту предлагается использовать более динамический механизм для объединения желаемой информации:

  • a std::string и +
  • a std::ostringstream
  • буфер символов и, возможно, strcat и / или sprintf()

Наиболее очевидные способы их использования не работают или не работают:

// temporaries...
throw (std::string("couldn't parse input: ") + input).c_str();
throw (std::ostringstream() << "error line " << __LINE__).str().c_str();
char buf[1024]; sprintf(buf, "error line %ld%", __LINE); throw buf;

// not thread-safe
static char buf...

Даже если программист знает, что ничего из этого не нужно, у него все равно будет время найти весь клиентский код, который должен начать принимать более богатый тип значения, особенно если другое throw / catch использование const char* сохраняется.

Таким образом, использование класса, который встраивает гибкое std::string описание по значению , очень важно для написания поддерживаемого кода.

5 голосов
/ 06 июня 2011

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

catch(const char* const errorMessage) {...}

1-й const, означает добавление возможности получать любой char массив char* const char* char[] const char[]

2-йconst означает, что errorMessage не предназначен для изменения в catch блоке

1 голос
/ 06 июня 2011

std :: exception (или, по крайней мере, std :: runtime_error) содержит строку, к которой можно получить доступ через метод what ().Лучшее, что вы можете сделать, - это использовать его, поскольку он является стандартным, и другой код может ожидать этого, и поскольку он в любом случае служит вашим целям.

1 голос
/ 06 июня 2011

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

0 голосов
/ 21 февраля 2014

Я думаю, что это намного проще.:).

#include <iostream>
#include <exception>

using namespace std;

int main() {
    try {
        throw runtime_error("This is an Error"); 
    }catch (exception& e){
        cout << "Exception: " << e.what() << endl; 
    }
    return 0; 
}
0 голосов
/ 10 июня 2011

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

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

В нашем приложении наши исключения получены из std :: exception. Они содержат тип ошибки (перечисление), сообщение об ошибке отладки (включая номер файла / строки) и локализованную строку ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...