Incrementing in C++ - Когда использовать x++ или ++x?

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

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

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

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

10 ответов


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

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

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

поэтому просто решите, какую логику вы пишете.

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


Скотт Мейерс говорит вам предпочесть префикс, за исключением тех случаев, когда логика диктует, что постфикс подходит.

" более эффективный C++ " пункт #6


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

вы должны предпочесть pre-increment оператор (++iter) для post-increment оператор (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   }

очевидно, что это менее эффективно, чем pre-increment.

Pre-increment не создает временный объект. Это может сделать значительно разница, если ваш объект дорог для создания.


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

пример:

pre.cpp:

#include <iostream>

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

пост.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"

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

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

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

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

i++;
x += i;

или

x += i;
i++;

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


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


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

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

Edit: исправлено смешение префикса и суффикса


понимание синтаксиса языка важно при рассмотрении ясности кода. Рассмотрите возможность копирования символьной строки, например, с post-increment:

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] является функцией, которая является дорогостоящей или имеет побочные эффекты. Существенной разницей может быть выходное значение индекса.


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

форма префикса (++x,--x) следует правилу изменить-далее-использовать.

Пример 1:

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

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

результате

12    10    10 

Пример 2:

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

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

это выход в Turbo C++ будет

48 13

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

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