Производительность попала в С++-стиле?
Я новичок в стилях стиля С++, и я обеспокоен тем, что использование стилей в стиле С++ приведет к потере производительности моего приложения, потому что у меня есть срочный критический срок в моей рутинной процедуре прерывания.
Я слышал, что некоторые броски даже бросают исключения!
Я хотел бы использовать приведения стиля С++, потому что это сделает мой код более "надежным". Тем не менее, , если есть какой-либо удар производительности, то я, вероятно, не буду использовать приведения стиля С++ и вместо этого потрачу больше времени на тестирование кода, использующего приведения в стиле C.
Проводили ли какие-либо строгие тесты/профилирование для сравнения производительности прикладов стиля С++ с кастами стиля C?
Каковы были ваши результаты?
Какие выводы вы сделали?
Ответы
Ответ 1
Если приведение стиля С++ может быть концептуально заменено на C-стиль, то накладные расходы не будут. Если он не может, как и в случае dynamic_cast
, для которого нет C-эквивалента, вы должны оплатить стоимость так или иначе.
В качестве примера приведен следующий код:
int x;
float f = 123.456;
x = (int) f;
x = static_cast<int>(f);
генерирует идентичный код для обоих приведений с VС++ - код:
00401041 fld dword ptr [ebp-8]
00401044 call __ftol (0040110c)
00401049 mov dword ptr [ebp-4],eax
Единственный С++-прилив, который может бросать, dynamic_cast
при бросании к ссылке. Чтобы избежать этого, нарисуйте указатель, который вернет 0, если сбой выполняется.
Ответ 2
Единственный, у кого есть дополнительные затраты во время выполнения, dynamic_cast
, который имеет возможности, которые невозможно воспроизвести напрямую с помощью приведения стиля C в любом случае. Поэтому у вас нет проблем.
Самый простой способ убедиться в этом - дать указание вашему компилятору генерировать вывод ассемблера и изучить созданный им код. Например, в любом программном компиляторе, состоящем из строгого режима, reinterpret_cast
полностью исчезнет, потому что это просто означает "идти вслепую вперед и притворяться, что данные имеют этот тип".
Ответ 3
Почему был бы удар производительности? Они выполняют ту же функциональность, что и C cast. Единственное отличие заключается в том, что они усваивают больше ошибок во время компиляции, и их легче искать в исходном коде.
static_cast<float>(3)
в точности эквивалентен (float)3
и будет генерировать точно такой же код.
Учитывая a float f = 42.0f
reinterpret_cast<int*>(&f)
в точности эквивалентен (int*)&f
и будет генерировать точно такой же код.
И так далее. Единственное отличие, отличное от dynamic_cast
, которое, да, может вызвать исключение. Но это потому, что он делает то, что не может сделать C-стиль. Поэтому не используйте dynamic_cast
, если вам не нужны его функции.
Обычно безопасно предполагать, что компиляторы являются интеллектуальными. Учитывая два разных выражения, которые имеют одну и ту же семантику в соответствии со стандартом, обычно безопасно предположить, что они будут реализованы идентично в компиляторе.
К сожалению. Второй пример должен быть reinterpret_cast, а не dynamic_cast, конечно. Исправлено.
Хорошо, просто для того, чтобы сделать это абсолютно ясно, вот что говорит стандарт С++:
§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-стиль должен быть медленнее. (конечно, это не так, потому что компилятор генерирует один и тот же код в любом случае, но он более правдоподобен, чем приведение в стиле С++ медленнее.)
Ответ 4
Есть четыре стили стиля С++:
-
const_cast
-
static_cast
-
reinterpret_cast
-
dynamic_cast
Как уже упоминалось, первые три являются операциями во время компиляции. Для их использования не существует штрафного времени. Это сообщения компилятору о том, что данные, которые были объявлены одним способом, должны быть доступны другим способом. "Я сказал, что это был int*
, но позвольте мне получить доступ к нему, как если бы это было char*
, указывающее на sizeof(int) char
s" или "Я сказал, что эти данные доступны только для чтения, и теперь мне нужно передать его которая не будет изменять его, но не принимает параметр в качестве ссылки на константу."
Помимо искажения данных путем кастомизации к неправильному типу и перебора данных (всегда возможность с помощью C-стиля) наиболее распространенная проблема времени выполнения с этими приведениями - это данные, которые фактически объявлены const
, возможно, не могут быть закрыты неконстантно. Приведение чего-то объявленного const
в неконстантное, а затем его изменение undefined. Undefined означает, что вам даже не гарантировано получить сбой.
dynamic_cast
- это конструкция времени выполнения и должна иметь затраты времени выполнения.
Значение этих отливок заключается в том, что они конкретно говорят, что вы пытаетесь сделать из/в, выставлять визуально и их можно искать с помощью мозговых инструментов. Я бы порекомендовал их использовать с использованием стилей C-стиля.
Ответ 5
При использовании dynamic_cast
во время выполнения выполняется несколько проверок, чтобы вы не делали что-то глупое (больше в список рассылки GCC) стоимость одного dynamic_cast
зависит от того, сколько классов затронуто, какие классы затронуты и т.д.
Если вы действительно уверены, что бросок безопасен, вы все равно можете использовать reinterpret_cast
.
Ответ 6
Несмотря на то, что я согласен с утверждением "только с любой дополнительной стоимостью во время выполнения dynamic_cast
", имейте в виду, что могут быть различия в компиляторах.
Я видел несколько ошибок, поданных против моего текущего компилятора, где генерация или оптимизация кода были немного разными в зависимости от того, используете ли вы стиль C-style и С++ static_cast
.
Итак, если вы беспокоитесь, проверьте разборку на горячих точках. В противном случае просто избегайте динамических бросков, когда они вам не нужны. (Если вы отключите RTTI, вы не сможете использовать dynamic_cast
в любом случае.)
Ответ 7
Каноническая истина - это сборка, поэтому попробуйте оба и посмотрите, есть ли у вас другая логика.
Если вы получаете ту же самую сборку, нет никакой разницы - ее не может быть. Единственное место, которое вам действительно нужно придерживаться со старыми кастами C, - это чистые подпрограммы и библиотеки C, где нет смысла вводить зависимость С++ только для литья типов.
Одна вещь, о которой нужно знать, это то, что броски происходят повсюду в приличном размере кода. За всю свою карьеру я никогда не искал "все броски" в логике - вы склонны искать отливки для определенного ТИПА типа "А", а поиск по "(А)" обычно так же эффективен, как и что-то вроде "static_cast <A> ". Используйте новые роли для таких вещей, как проверка типов и т.д., А не потому, что они выполняют поиск, вы никогда не сделаете этого легче.