Does throw() (то есть __declspec (nothrow)) дает реальные преимущества в Visual С++?
Сосредоточив внимание на Visual С++, вы когда-либо испытывали значительную прирост производительности в С++-кодексе, используя спецификацию throw()
(т.е. __declspec(nothrow)
)?
Помогает ли это оптимизатору?
Существуют ли какие-либо тесты, показывающие прирост производительности?
Я нашел разные (противоположные) советы в Интернете:
Обоснование обоснования исключений - против throw()
, вместо этого Ларри Остерман, похоже, поддерживает это в своем блоге: Зачем добавлять методы throw() к вашим методам?
(Я хотел бы уточнить, что меня интересует специфический код VС++; я знаю, что в GCC спецификация throw()
может фактически быть "пессимизацией" из-за проверки времени выполнения.)
P.S. Чтение заголовков ATL, я обнаружил, что throw()
используется повсеместно; Более того, я нашел удобный класс С++ RAII unique_handle
в этой статье MSDN, в которой также используется спецификация throw()
.
Ответы
Ответ 1
Компилятор MSVC рассматривает его как подсказку оптимизации, да.
Boost должен быть кросс-платформенным, им нужно искать что-то безопасное и эффективное для множества компиляторов. И, как говорят операторы boost, некоторые компиляторы могут генерировать более медленный код, если указан throw()
, и во многих случаях компиляторы могут вывести, что исключение не выбрасывается независимо от того, существует ли спецификация throw()
, поэтому для Boost, наиболее безопасного подход заключается в том, чтобы просто никогда не использовать спецификации throw.
Но если вы специально нацеливаете MSVC, то throw()
эффективно сообщает компилятору не генерировать код обработки исключений для этой функции, что может привести к ускорению в тех случаях, когда функция слишком сложна для компилятора, чтобы определить, что никакое исключение не может быть брошено.
Ответ 2
Я добавляю его, но его не помогать оптимизатору, чтобы он помог мне написать более правильный код.
class X
{
public:
void swap(X& rhs) throw(); // Swap better not ever throw
// If it does there is something else
// much more seriously wrong
};
Ответ 3
Основная проблема с throw()
заключается в том, что код внутри функции, помеченный как throw()
, может вызывать.
Например, это будет отлично работать:
void foo() throw()
{
throw "haha\n";
}
int main()
{
try {
foo();
}
catch(const char* s) {
std::cout << s;
}
return 0;
}
Обратите внимание, что foo не будет throw
до main
, причины. И вы не поймаете исключение (как если бы вы прокомментировали спецификатор throw()
). Вместо этого компилятор будет обертывать функцию кода блоком try{}catch()
. Когда генерируется исключение, он будет обрабатываться глобальным обработчиком (это будет означать, что ваша программа по умолчанию по умолчанию).
Обратите внимание, что компилятор должен обернуть функциональный код блоком try{}cath()
, если только компилятор не уверен, что внутренний код не имеет возможности генерировать исключение.
В результате может быть выполнена некоторая оптимизация с вызывающим абонентом foo
, но вещи становятся более сложными внутри foo
.
EDIT:
Вещи с __declspec(nothrow)
отличаются: Microsft сообщает,
Этот атрибут сообщает компилятору, что объявленная функция и функции, которые он вызывает, никогда не генерируют исключение.
Это означает, что компилятор может опустить try{}catch()
код оболочки.
EDIT2
На самом деле Microsoft нарушает стандартное поведение и не генерирует warpper для throw()
. Ну, тогда вы можете использовать throw()
для повышения производительности.