Преинкремент и постинкремент

859
06 ноября 2017, 19:28

Задали вопрос на учебе, что больше потребляет ресурсов ++i или i++. Самостоятельно инфо не нашёл, прошу подсказать где искать.

Answer 1

Согласно спецификации языка, разница между пре- и постинкрементом состоит в том, что при вычислении выражения значением результат является в одном случае старое, а в другом — новое значение инкрементируемой переменной. В случае простого применения в форме x++; (например, такое часто встречается в циклах) возвращаемое значение не используется, и смысл обеих форм строго одинаков, так что они компилируются в одинаковый объектный код.

Даже если оператор инкремента переопределён, разницы нет, т. к. (в отличие от C++) нет возможности иметь различные определения для пре- и постинкрементов.

Откуда растут ноги у этого вопроса? А вот откуда. В древние времена были наивные компиляторы языка C (и, возможно, C++), которые не умели оптимизировать код. И если они компилировали прямолинейно, то код получался таким:

// x++
int temp = x;
x = x + 1;
// результат = temp; но он не нужен, так что он отбрасывается

и

// ++x;
x = x + 1;
// результат = x; но он не нужен, так что он отбрасывается

Ваш преподаватель, вероятно, слыхал об этом, и ждёт от вас ответа о том, что необходимо ручной оптимизацией убрать ненужную временную переменную. Он неправ, отстал от реальности на вечность и тянет вас в эпоху трилобитов.

В реальности последние как минимум 10 лет компиляторы умеют делать оптимизации намного лучше людей, и в частности прекрасно умеют выбрасывать никому не нужные временные переменные. Так что разницы в сгенерированном коде просто не будет, что можно видеть даже для C++ здесь.* (Если вы, конечно, не отключите оптимизации.)

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

*Например, из таких двух функций:

volatile int x; // угадайте, что будет, если убрать volatile :-P
int pre(int num)
{
    for (int i = 0; i < num; ++i)
        x = i;
}
int post(int num)
{
    for (int i = 0; i < num; i++)
        x = i;
}

gcc 7.2 с ключом -O3 производит

pre(int):
  test edi, edi
  jle .L2
  xor eax, eax
.L3:
  mov DWORD PTR x[rip], eax
  add eax, 1
  cmp edi, eax
  jne .L3
.L2:
  rep ret
post(int):
  test edi, edi
  jle .L6
  xor eax, eax
.L8:
  mov DWORD PTR x[rip], eax
  add eax, 1
  cmp edi, eax
  jne .L8
.L6:
  xor eax, eax
  ret

А с ключом -Os вообще

pre(int):
  xor eax, eax
.L3:
  cmp eax, edi
  jge .L2
  mov DWORD PTR x[rip], eax
  inc eax
  jmp .L3
.L2:
  ret
post(int):
  jmp pre(int)
Answer 2

В C# разницы между пост- и преинкрементом нет, в C++ (отвечая на Ваш комментарий с ?) ситуация следующая: как правило, постинкремент реализуется посредством преинкремента и возвращает первоначальное значение переменной. Каноническая форма постинкремента:

T T::operator++(int)
{
    T old(*this);
    ++*this;
    return old;
}

Как видите, создается временная переменная old. Каноническая форма преинкремента:

T& T::operator++()
{
    // increment your object here
    return *this;
}

Поэтому быстрее будет работать преинкремент.

READ ALSO
Как работает auto-property?

Как работает auto-property?

Имеется такой код :

245
Не удаётся правильно извлечь Date из DateTime

Не удаётся правильно извлечь Date из DateTime

Как было указано в заголовке, не получается правильно извлечь Date из переменной DateTimeВот мой код:

248
Как создать новый проект в существующем решении в Visual Studio на Mac?

Как создать новый проект в существующем решении в Visual Studio на Mac?

Как создать новый проект в существующем решении в Visual Studio на Mac?

236