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



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



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



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



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

2382   10  

10 ответов:

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

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

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

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

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

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

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

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

вы должны предпочесть пре-инкремент оператор (++iter) для пост-инкремента оператор (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/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"

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

редактировать: исправлена путаница с префиксом и суффиксом обозначения

понимание синтаксиса языка важно при рассмотрении ясности кода. Рассмотрите возможность копирования символьной строки, например, с помощью 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]);

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

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

Префиксная форма (++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
  • Примечание: многократное использование операторов инкремента / декремента на одной переменной в одном выражении не рекомендуется. Обработка / результаты таких
    выражения варьируются от компилятора к компилятору.

Comments

    Ничего не найдено.