Спецификации исключений при выводе из std :: exception в C ++ 11 - PullRequest
9 голосов
/ 26 ноября 2010

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

#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

ошибка: более слабый спецификатор броска для'virtual const char * InvalidPathException :: what () const'

ошибка: переопределение 'virtual const char * std :: exception :: what () const throw ()'

Совершенно верно, так как я переопределяю метод std::exception what(), который действительно имеет спецификатор исключения throw().Но так как часто будет проинформирован , мы не должны использовать спецификаторы исключений.И, насколько я понимаю, они устарели в C ++ 11 , но, очевидно, еще не в GCC с -std = c ++ 0x.

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

В качестве альтернативы, есть ли способ обойти эту ошибку, заданную GCC?

1 Ответ

7 голосов
/ 26 ноября 2010

Пусто throw спецификации полезны, поскольку они фактически позволяют оптимизировать компилятор на сайте вызывающей стороны, как знает Википедия (у меня нет под рукой технической цитаты).

И по причинам возможностей оптимизации nothrow-спецификации не устарели в следующем стандарте, они просто больше не похожи на throw (), а называются noexcept. Ну да, и они работают немного по-другому.

Здесь - обсуждение noexcept, в котором также подробно объясняется, почему традиционные спецификации nothrow-prohobit оптимизируются на сайте вызываемого абонента.

Как правило, вы платите за каждую имеющуюся у вас throw спецификацию, по крайней мере, с помощью полностью совместимого компилятора, который, по-видимому, не всегда был у GCC. Эти throw спецификации должны быть проверены во время выполнения, даже пустые. Это происходит потому, что если возникает исключение, которое не соответствует спецификации throw, разматывание стека должно происходить в пределах этого стекового фрейма (так что вам нужен код для этого в дополнение к проверке соответствия) и затем std::unexpected должен называться. С другой стороны, вы потенциально экономите время / пространство для каждой пустой throw спецификации, поскольку компилятор может делать больше предположений при вызове этой функции. Я выдохну, сказав, что только профилировщик может дать вам окончательный ответ о том, страдает или улучшается ваш конкретный код с помощью ( пусто !) throws спецификации.

В качестве обходного пути к вашей реальной проблеме может ли работать следующее?

  • Введите #define NOTHROW throw () и используйте его для what вашего исключения и других вещей.
  • Когда GCC реализует noexcept, переопределите NOTHROW.

Обновление

Как отмечает @James McNellis, throw () будет совместимым с прямой пересылкой. В этом случае я предлагаю просто использовать throw () там, где вам нужно, и, кроме этого, если есть сомнения, профиль.

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