Хит производительности от бросков стиля C ++? - PullRequest
53 голосов
/ 23 марта 2009

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

Я слышал, что некоторые броски будут даже генерировать исключения!

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


Кто-нибудь проводил тщательное тестирование / профилирование, чтобы сравнить производительность приведения в стиле C ++ и приведения в стиле C?

Какими были ваши результаты?

Какие выводы вы сделали?

Ответы [ 7 ]

82 голосов
/ 23 марта 2009

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

В качестве примера приведен следующий код:

int x;
float f = 123.456;

x = (int) f;
x = static_cast<int>(f);

генерирует идентичный код для обоих приведений с VC ++ - код:

00401041   fld         dword ptr [ebp-8]
00401044   call        __ftol (0040110c)
00401049   mov         dword ptr [ebp-4],eax

Единственное приведение C ++, которое может генерировать, - это dynamic_cast при приведении к ссылке. Чтобы избежать этого, приведите к указателю, который вернет 0 в случае сбоя.

39 голосов
/ 23 марта 2009

Единственный, с какими-либо дополнительными затратами во время выполнения, это dynamic_cast, у которого есть возможности, которые в любом случае не могут быть воспроизведены непосредственно с использованием стиля C Так что у вас нет проблем.

Самый простой способ убедиться в этом - дать вашему компилятору команду генерировать выходные данные ассемблера и изучить код, который он генерирует. Например, в любом разумно реализованном компиляторе reinterpret_cast вообще исчезнет, ​​потому что это просто означает «идти вслепую и притворяться, что данные этого типа».

16 голосов
/ 23 марта 2009

Зачем было бы падение производительности? Они выполняют точно те же функции, что и C-приведения. Единственное отличие состоит в том, что они отлавливают больше ошибок во время компиляции, и их проще искать в исходном коде.

static_cast<float>(3) в точности эквивалентно (float)3 и генерирует точно такой же код.

Учитывая float f = 42.0f reinterpret_cast<int*>(&f) в точности эквивалентен (int*)&f и генерирует точно такой же код.

И так далее. Единственный различий, который отличается, это dynamic_cast, который, да, может вызвать исключение. Но это потому, что он делает то, что не может делать актерский стиль. Так что не используйте dynamic_cast, если вам не нужны его функции.

Обычно можно с уверенностью предположить, что авторы компиляторов умны. Учитывая два разных выражения, которые имеют одинаковую семантику в соответствии со стандартом, обычно можно с уверенностью предположить, что они будут реализованы одинаково в компиляторе.

Упс : Второй пример должен быть reinterpret_cast, а не dynamic_cast, конечно. Исправлено сейчас.

Хорошо, просто чтобы прояснить ситуацию, вот что говорит стандарт C ++:

§5.4.5:

Преобразования, выполненные

  • a const_cast (5.2.11)
  • a static_cast (5.2.9)
  • a static_cast, за которым следует const_cast
  • a reinterpret_cast (5.2.10) или
  • a reinterpret_cast, за которыми следует const_cast.

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

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

15 голосов
/ 24 марта 2009

Существует четыре приведения в стиле C ++:

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

Как уже упоминалось, первые три являются операциями времени компиляции. За их использование не взимается штраф. Это сообщения компилятору о том, что данные, которые были объявлены одним способом, должны быть доступны другим способом. «Я сказал, что это int*, но позвольте мне получить к нему доступ, как если бы это был char*, указывающий на sizeof(int) char с» или «Я сказал, что эти данные доступны только для чтения, и теперь мне нужно передать их функция, которая не изменяет его, но не принимает параметр в качестве константной ссылки. "

Помимо повреждения данных при приведении к неправильному типу и поиска данных (всегда возможна при приведении в стиле C), наиболее распространенная проблема времени выполнения с этими приведениями - это данные, которые фактически объявлены неконстантным. Приведение чего-либо, объявленного const, к неконстантному, а затем его изменение не определено. Не определено означает, что вам даже не гарантирован сбой .

dynamic_cast является конструкцией во время выполнения и должна иметь стоимость во время выполнения.

Ценность этих приведений заключается в том, что они конкретно говорят о том, что вы пытаетесь разыграть из / в, высовываетесь визуально, и их можно искать с помощью инструментов с мертвой головой. Я бы порекомендовал использовать их по сравнению с приведением в стиле C.

4 голосов
/ 23 марта 2009

При использовании dynamic_cast во время выполнения выполняется несколько проверок, чтобы вы не допустили глупостей (подробнее в списке рассылки GCC ), стоимость одного dynamic_cast зависит от количества затронутых классов какие классы затронуты и т. д.
Если вы действительно уверены, что приведение является безопасным, вы все равно можете использовать reinterpret_cast.

3 голосов
/ 23 марта 2009

Несмотря на то, что я согласен с утверждением «единственное, что требует дополнительных затрат во время выполнения, это dynamic_cast», имейте в виду, что могут быть различия, характерные для компилятора.

Я видел несколько ошибок в моем текущем компиляторе, где генерация или оптимизация кода немного отличались в зависимости от того, используете ли вы стиль C или C ++ static_cast cast.

Так что, если вы беспокоитесь, проверьте разборку в горячих точках. В противном случае просто избегайте динамических приведений, когда они вам не нужны. (Если вы отключите RTTI, вы все равно не сможете использовать dynamic_cast.)

1 голос
/ 21 июля 2014

Каноническая истина - это сборка, так что попробуйте оба и посмотрите, если вы получаете другую логику.

Если вы получаете точно такую ​​же сборку, разницы нет - не может быть. Единственное место, где вам действительно нужно придерживаться старых приведений C, - это чистые процедуры и библиотеки C, где нет смысла вводить зависимость C ++ только для приведения типов.

Одна вещь, о которой следует помнить, это то, что приведение происходит повсюду в приличном размере кода. За всю свою карьеру я никогда не искал «все приведения» в какой-то логике - вы склонны искать приведения к определенному ТИПУ, например «А», и поиск по «(А)» обычно так же эффективен что-то вроде "static_cast ". Используйте более новые приведения для таких вещей, как проверка типов и т. Д., А не потому, что они делают поиск, который вы никогда не сделаете проще.

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