2013-04-03 2 views
1

В соответствии с «Google C++ Style Guide», когда возвращаемое значение игнорируется, форма «pre» (++i) не менее эффективна, чем форма «post» (i++) и часто более эффективна ».Почему ++ i эффективнее i ++?

В руководстве разъясняется, почему, но я не совсем понимаю. Мысли? Может быть, кто-то мог бы привести пример этой концепции?

+0

С встроенными типами, они одинаковы. С пользовательским типом префикс, естественно, менее сложный. –

+1

Это не обязательно: http://stackoverflow.com/questions/24886/is-there-a-performance-difference-between-i-and-i-in-c – maditya

+0

++ i увеличивает значение i 'поэтому, поэтому в один такт цикла значение увеличивается на что-то новое. В то время как i ++ занимает 2 такта. Насколько эффективность идет, что спорно, учитывая скорость тактового цикла. – smac89

ответ

10

i++ Приращения i и возвращает начальное значение i. Что означает:

int i = 1; 
i++; // == 1 but i == 2 

Но ++i возвращает фактическое измененное значение:

int i = 1; 
++i; // == 2 and i == 2 too, so no need for a temporary variable 

В первом случае, компилятор должен создать временную переменную (если используется) для возвращения 1 вместо 2 (в случай, когда это не константа, а динамическое значение, например, возврат из вызова).

Во втором случае это не обязательно. Таким образом, второй случай гарантированно будет как минимум эффективным.

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

В любом случае, мы говорим о крайне незначительном воздействии.

Но на более сложных объектах, например iterators-подобных объектах, наличие временного состояния может быть довольно медленным, если итерировать миллионы раз.

Эмпирической

Используйте префикс версию, если вы специально не хотите постфиксную семантики.

2

Цитируя:

http://www.parashift.com/c++-faq/increment-pre-post-speed.html

++ я иногда быстрее, и никогда не медленнее, чем, я ++.

Для встроенных типов, таких как int, это не имеет значения: ++ i и i ++ имеют одинаковую скорость. Для типов классов, таких как итераторы, ++ i очень хорошо может быть быстрее, чем i ++, поскольку последний может сделать копию этого объекта.

Накладные расходы i ++, если они есть вообще, вряд ли будут иметь практическое значение, если ваше приложение не связано с ЦП. Например, если ваше приложение проводит большую часть своего времени, ожидая, что кто-то щелкнет мышью, выполнив операции ввода-вывода на базе ввода-вывода, сетевого ввода-вывода или базы данных, это не повредит вашей производительности, чтобы тратить несколько циклов процессора. Однако так же легко набрать ++ i как i ++, так почему бы не использовать первое, если вам действительно не нужно старое значение i.

Итак, если вы пишете i ++ в качестве утверждения, а не как часть более крупного выражения, почему бы не просто написать ++ i вместо этого? Вы никогда ничего не теряете, и иногда получаете что-то. Программисты Old line C используются для записи i ++ вместо ++ i. Например., Они скажут,

for (i = 0; i < 10; i++) .... 

Поскольку это использует я ++ как утверждение, а не как часть большего выражения, то вы можете использовать ++ я вместо этого. Для симметрии я лично защищаю этот стиль, даже если он не улучшает скорость, например, для внутренних типов и типов классов с операторами postfix, которые возвращают void.

0

i ++ - значение увеличивается после использования i ++ i - значение немедленно увеличивается.

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

0

Оператор приращения (или декремента) включает в себя две операции: приращение и принятие одного из двух значений (старых или новых) в результате выражения. Разница заключается в том, что нужно предпринять.

Если вы берете предварительную форму, вы сначала увеличиваете, а затем берете значение, новое.

Вы рассказываете постформу, вы берете старую ценность, храните ее, увеличиваете, ставите новую в старую позицию и возвращаете старую. Это звучит сложнее - и это так.

Но если возвращаемое значение выражения игнорируется, оно не должно иметь никакого значения вообще, независимо от того, есть ли у вас встроенный тип или объект.

0

Для итераторов и других типов шаблонов используйте предварительный приращение.

+0

Вопрос был о том, «почему это так». – glglgl

+0

Это потому, что для пост-инкремента (или декремента) требуется копирование i, которое является значением выражения. Если i является итератором или другим нескалярным типом, копирование может быть дорогостоящим. – llSpectrell

0

Это происходит потому, что, когда вы postincrement, вы должны:

  1. Измените значение и в то же время
  2. присвоить старое значение для чего-то еще.

Просто вы должны иметь две копии этой переменной, а также копирование и удаление является то, что требуется дополнительное время ...

Смежные вопросы