Вопрос

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

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

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

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

Это было полезно?

Решение

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

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

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

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

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

Другие советы

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

" более эффективный C ++ " пункт № 6 - для меня этого достаточно.

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

  

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

И на странице 34:

  

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

Из 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   }
  

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

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

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

пример:

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

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

Редактировать: исправлено смешение префикса и суффиксной нотации

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

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

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

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

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

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

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

Пример 1:

Когда несколько значений каскадируются с помощью <<, используя расчет тогда вычисления (если есть) будут происходить справа налево, а печать - слева направо, например, (если вал если изначально 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
  • Примечание:Множественное использование операторов приращения/уменьшения по той же переменной в одном выражении не рекомендуется.Обработка/результаты таких
    выражения варьируются от компилятора к компилятору.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top