Это пример того, что я часто делаю, когда хочу добавить некоторую информацию к исключению:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Есть способ сделать это лучше?
std∷exception
вас нет конструктора сchar*
arg.std::string
него есть неявный конструктор, который принимаетconst char*
...std::exception
дочерних классов MS , и используется их версиямиstd::runtime_error
иstd::logic_error
. Помимо тех, что определены стандартом, версия MSVS<exception>
также включает в себя еще два конструктора, один из которых принимает,(const char * const &)
а другой принимает(const char * const &, int)
. Они используются для установки частной переменнойconst char * _Mywhat
; если_Mywhat != nullptr
, то поwhat()
умолчанию возвращает его. Код, который полагается на него, вероятно, не переносится.Ответы:
Вот мое решение:
Пример:
источник
Стандартные исключения могут быть построены из
std::string
:Обратите внимание, что базовый класс не
std::exception
может быть построен таким образом; вы должны использовать один из конкретных производных классов.источник
Существуют различные исключения , такие как
runtime_error
,range_error
,overflow_error
,logic_error
и т.д .. Вам нужно передать строку в его конструктор, и вы можете объединить все , что вы хотите , чтобы ваше сообщение. Это просто строковая операция.Вы также можете использовать
boost::format
это так:источник
Следующий класс может оказаться весьма кстати:
Пример использования:
источник
throw std::runtime_error(sprintf("Could not load config file '%s'", configfile.c_str()))
throw std::runtime_error("Could not load config file " + configfile);
(преобразовываяstd::string
при необходимости тот или иной аргумент в ).printf
C ++ 11 неизбежно появятся переносимые типы и друзья. Буфер фиксированного размера - это и благословение, и проклятие: он не дает сбоев в ситуациях с нехваткой ресурсов, но может усечь сообщение. Я считаю обрезание сообщения об ошибке лучшим вариантом, чем отказ. Кроме того, удобство форматных строк было доказано многими разными языками. Но вы правы, это во многом дело вкуса.Используйте оператор строкового литерала, если C ++ 14 (
operator ""s
)или определите свой собственный, если в С ++ 11. Например
Тогда ваша инструкция throw будет выглядеть так
что выглядит красиво и чисто.
источник
По-настоящему приятнее было бы создать класс (или классы) для исключений.
Что-то вроде:
Причина в том, что исключения намного предпочтительнее, чем просто передача строки. Предоставляя различные классы для ошибок, вы даете разработчикам возможность обработать конкретную ошибку соответствующим образом (а не просто отображать сообщение об ошибке). Люди, перехватывающие ваше исключение, могут быть сколь угодно конкретными, если вы используете иерархию.
а) Возможно, потребуется знать конкретную причину
а) другой не хочет знать подробностей
Вдохновение по этой теме можно найти в https://books.google.ru/books?id=6tjfmnKhT24C. главе 9.
Кроме того , вы можете предоставить пользовательское сообщение тоже, но будьте осторожны - это не безопасно , чтобы составить сообщение с любым
std::string
илиstd::stringstream
или любым другим способом , который может вызвать исключение .Как правило, нет разницы, выделяете ли вы память (работаете со строками в стиле C ++) в конструкторе исключения или непосредственно перед выбросом -
std::bad_alloc
исключение может быть сгенерировано до того, которое вам действительно нужно.Итак, буфер, выделенный в стеке (как в ответе Максима), является более безопасным способом.
Это очень хорошо объясняется на http://www.boost.org/community/error_handling.html.
Итак, более приятным способом было бы конкретный тип исключения и избегать составления отформатированной строки (по крайней мере, при выбросе).
источник
Возникла аналогичная проблема, когда создание пользовательских сообщений об ошибках для моих пользовательских исключений приводит к уродливому коду. Это было моим решением:
Это разделяет логику создания сообщений. Первоначально я думал о том, чтобы переопределить what (), но тогда вам нужно где-то записать свое сообщение. std :: runtime_error уже имеет внутренний буфер.
источник
Может быть, это?
Он создает временный поток ostringstream, вызывает операторы << по мере необходимости, а затем вы заключаете его в круглые скобки и вызываете функцию .str () для оцененного результата (который является потоком ostring) для передачи временного std :: string конструктору из runtime_error.
Примечание: поток ostringstream и строка являются временными значениями r и поэтому выходят из области видимости после окончания этой строки. Конструктор вашего объекта исключения ДОЛЖЕН принимать входную строку, используя семантику копирования или (лучше) перемещения.
Дополнительно: я не обязательно считаю этот подход «лучшей практикой», но он действительно работает и может быть использован в крайнем случае. Одна из самых больших проблем заключается в том, что этот метод требует выделения кучи, поэтому оператор << может бросать. Вероятно, вы этого не хотите; однако, если вы попадете в это состояние, у вас, вероятно, будет больше проблем, о которых стоит беспокоиться!
источник