Спецификации исключений при выводе из std::exception в C++11
У меня есть класс исключения следующим образом:
#include <exception>
struct InvalidPathException : public std::exception
{
explicit InvalidPathException() {}
const char* what() const;
};
const char*
InvalidPathException::what() const {
return "Path is not valid";
}
При компиляции в GCC 4.4 с -Wall -std= C++0x
ошибка: более слабый спецификатор броска для 'виртуального константного символа * InvalidPathException::what() const'
ошибка: переопределение 'виртуального const char* std::exception::what() const throw ()'
Совершенно верно, так как я переопределяю std::exception
"s what()
метод, который действительно имеет throw()
спецификатор исключения. Но, как часто сообщают, мы не должны использовать спецификаторы исключений. И, насколько я понимаю, они устарели в C++ 11, но, очевидно, еще не в GCC с -std = C++0x.
Так что я был бы заинтересован в наилучшем подходе на данный момент. В коде, который я разрабатываю, я беспокоюсь о производительности и поэтому беспокоюсь о часто упоминаемых издержках throw()
, но на самом деле это накладные расходы настолько серьезны? Правильно ли я думаю, что я буду страдать только тогда, когда what()
фактически вызывается, что было бы только после того, как было сгенерировано такое исключение (и аналогично для других методов, унаследованных от std:: exception, которые все имеют throw()
спецификаторы)?
В качестве альтернативы, есть ли способ обойти эту ошибку, данную GCC?
1 ответ
Пустой throw
спецификации полезны, так как на самом деле они позволяют оптимизировать компилятор на сайте вызывающей стороны, как известно из Википедии (у меня нет технической цитаты).
И из-за возможностей оптимизации, nothrow-спецификации не устарели в следующем стандарте, они просто не похожи throw ()
больше, но называются noexcept
, Ну да, и они работают немного по-другому.
Вот обсуждение noexcept
это также подробно объясняет, почему традиционные спецификации nothrow оптимизируют работу сайта вызываемого абонента.
Как правило, вы платите за каждый throw
у вас есть спецификация, по крайней мере, с полностью совместимым компилятором, который GCC, по-видимому, не всегда был. Те throw
спецификации должны быть проверены во время выполнения, даже пустые. Это потому, что если возникает исключение, которое не соответствует throw
спецификация, раскрутка стека должна происходить в пределах этого стекового фрейма (так что вам нужен код для этого в дополнение к проверке соответствия), а затем std::unexpected
должен быть вызван. С другой стороны, вы потенциально экономите время / пространство для каждого пустого throw
спецификация как компилятор может сделать больше предположений при вызове этой функции. Я выдохну, сказав, что только профилировщик может дать вам окончательный ответ о том, страдает или улучшается ваш конкретный код (пусто!) throws
Спецификация.
В качестве обходного пути к вашей актуальной проблеме, могут ли работать следующие?
- Вводить
#define NOTHROW throw ()
и использовать его для вашего исключенияwhat
и другие вещи. - Когда GCC реализует
noexcept
, переопределитьNOTHROW
,
Обновить
Как отмечает @James McNellis, throw ()
будет вперед-совместимым. В этом случае я предлагаю просто использовать throw ()
где вы должны и, кроме этого, если есть сомнения, профиль.