Эффект от приведения в стиле C++?
Я новичок в кастах стиля C++, и я беспокоится, что использование приведений в стиле C++ испортит производительность моего приложения потому что у меня есть в режиме реального времени-критический срок в моей процедуре прерывания обслуживания.
Я слышал, что некоторые броски даже исключения!
Я хотел бы использовать приведения в стиле C++, потому что это сделает мой код более "надежным". Однако,если есть любой производительности тогда я, вероятно, не буду использовать C++ стиль бросает и вместо этого будет тратить больше времени на тестирование кода, который использует C-стиль бросает.
кто-нибудь проводил строгое тестирование/профилирование, чтобы сравнить производительность приведений стиля C++ с приведениями стиля C?
каковы были ваши результаты?
какие выводы вы сделали?
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) char
s " или " я сказал, что эти данные были доступны только для чтения, и теперь мне нужно передать его в функцию, которая не будет изменять его, но не принимает параметр в качестве ссылки на 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". Используйте новые приведения для таких вещей, как проверка типа и т. д., а не потому, что они делают поиск, который вы никогда не сделаете проще.