Подтвердить что ты не робот

Инкремент в С++ - Когда использовать x ++ или ++ x?

В настоящее время я изучаю С++, и некоторое время назад я узнал об инкрементальности. Я знаю, что вы можете использовать "++ x" , чтобы сделать инкремент раньше и "x ++" сделать это после.

Тем не менее, я действительно не знаю, когда использовать какой-либо из двух... Я никогда не использовал "++ x" , и вещи всегда работали нормально до сих пор - так, когда я должен его использовать?

Пример: В цикле for, когда предпочтительнее использовать "++ x" ?

Кроме того, может ли кто-нибудь объяснить, как работают разные приращения (или декременты)? Я был бы очень признателен.

4b9b3361

Ответ 1

Это не вопрос предпочтения, а логика.

x++ увеличивает значение переменной x после обработки текущего оператора.

++x увеличивает значение переменной x до обработки текущего оператора.

Так что просто решайте логику, которую вы пишете.

x += ++i будет увеличивать я и добавить я + 1 в x. x += i++ добавит я к x, а затем увеличит i.

Ответ 2

Скотт Майерс говорит вам предпочесть префикс, кроме тех случаев, когда логика будет определять, что postfix является подходящим.

"Более эффективный С++" item # 6 - это достаточный авторитет для меня.

Для тех, кто не владеет книгой, вот соответствующие цитаты. На странице 32:

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

И на стр. 34:

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

Ответ 3

Из cppreference при увеличении итераторов:

Вы должны предпочесть предварительный прирост operator (++ iter) для пост-приращения operator (iter ++), если вы не собираетесь для использования старого значения. Пост-инкремент обычно выполняется следующим образом:

   Iter operator++(int)   {
     Iter tmp(*this); // store the old value in a temporary object
     ++*this;         // call pre-increment
     return tmp;      // return the old value   }

Очевидно, что он менее эффективен, чем предварительно приращение.

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

Ответ 4

Я просто хочу заметить, что сгенерированный код одинаков, если вы используете pre/post incrementation, где семантика (pre/post) не имеет значения.

Пример:

pre.cpp:

#include <iostream>

int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}

post.cpp:

#include <iostream>

int main()
{

  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"

Ответ 5

Самое главное, что нужно помнить, imo, заключается в том, что x ++ должен вернуть значение до того, как наступило фактическое приращение - поэтому он должен сделать временную копию объекта (pre increment). Это менее эффективно, чем ++ x, который увеличивается на месте и возвращается.

Еще одна вещь, о которой стоит упомянуть, заключается в том, что большинство компиляторов смогут оптимизировать такие ненужные вещи, когда это возможно, например, обе опции приведут к тому же коду:

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)

Ответ 6

Я согласен с @BeowulfOF, хотя для ясности я всегда выступал за разделение утверждений, чтобы логика была абсолютно ясной, то есть:

i++;
x += i;

или

x += i;
i++;

Итак, я отвечаю, что если вы пишете чистый код, тогда это редко имеет значение (и если это имеет значение, то ваш код, вероятно, недостаточно ясен).

Ответ 7

Вы правильно объяснили разницу. Это просто зависит от того, хотите ли вы увеличивать x до каждого прогона через цикл или после этого. Это зависит от вашей логики программы, что подходит.

Важным отличием при работе с STL-Итераторами (которые также реализуют эти операторы) является то, что он ++ создает копию объекта, на который указывает итератор, затем увеличивает, а затем возвращает копию. ++, с другой стороны, делает инкремент первым, а затем возвращает ссылку на объект, на который теперь указывает итератор. Это в основном справедливо, когда каждый бит производительности считается или когда вы реализуете свой собственный STL-итератор.

Изменить: исправлено смешение префикса и нотации суффиксов

Ответ 8

Просто хотелось бы подчеркнуть, что ++ x ожидается быстрее, чем x ++ (особенно если x является объектом какого-либо произвольного типа), поэтому, если это не требуется по логическим причинам, ++ x следует использовать.

Ответ 9

Понимание синтаксиса языка важно при рассмотрении ясности кода. Рассмотрим копирование символьной строки, например, с последующим приращением:

char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
  b[i] = a[i];
} while (a[i++]);

Мы хотим, чтобы цикл выполнялся, встречая нулевой символ (который проверяет false) в конце строки. Для этого требуется тестирование значения пре-инкремента, а также увеличение индекса. Но не обязательно в таком порядке - способ кодирования этого с предварительным приращением будет:

int i = -1;
do {
  ++i;
  b[i] = a[i];
} while (a[i]);

Это вопрос вкуса, который более ясен, и если у машины есть несколько реестров, у обоих должно быть одинаковое время выполнения, даже если функция [i] является дорогостоящей или имеет побочные эффекты. Значимым отличием может быть значение выхода индекса.

Ответ 10

Постфиксная форма оператора ++, - следует правилу use-then-change,

Форма префикса (++ x, - x) следует правилу change-then-use.

Пример 1:

Когда несколько значений каскадируются с < используя cout, тогда вычисления (если они есть) выполняются справа налево, но печать выполняется слева направо, например, (если val, если первоначально 10)

 cout<< ++val<<" "<< val++<<" "<< val;

приведет к

12    10    10 

Пример 2:

В Turbo С++, если в выражении найдено несколько вхождений ++ или (в любой форме), то сначала вычисляются все префиксные формы, тогда выражение вычисляется и, наконец, выписываются окончательные формы, например,

int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;

Он выводится в Turbo С++ будет

48 13

В то время как он выводится в современном компиляторе, будет (потому что они строго следуют правилам)

45 13
  • Примечание. Множественное использование операторов приращения/уменьшения по одной переменной в одном выражении не рекомендуется. Обработка/результаты таких выражения варьируются от компилятора к компилятору.