Эффект от приведения в стиле C++?


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

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

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


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

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

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

7 51

7 ответов:

если приведение в стиле 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, если преобразование завершается неудачно.

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

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

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

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

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

и так на. Единственный бросок, который отличается dynamic_cast, который, Да, может бросить исключение. Но это потому, что он делает то, что C-style 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++.)

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

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

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

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

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

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

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

хотя я согласен с утверждением "только один с любой дополнительной стоимостью во время выполнения является dynamic_cast", имейте в виду, что могут быть специфические для компилятора различия.

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

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

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

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

одна вещь, чтобы быть в курсе, что броски происходят повсюду в приличном размере кусок кода. За всю мою карьеру Я никогда не искал "все приведения" в части логики - вы, как правило, ищете приведения к определенному типу, такому как "A", а поиск по "(A)"обычно так же эффективен, как и что-то вроде" static_cast". Используйте новые приведения для таких вещей, как проверка типа и т. д., а не потому, что они делают поиск, который вы никогда не сделаете проще.