Инкремент в С++ - Когда использовать x ++ или ++ x?
В настоящее время я изучаю С++, и некоторое время назад я узнал об инкрементальности.
Я знаю, что вы можете использовать "++ x" , чтобы сделать инкремент раньше и "x ++" сделать это после.
Тем не менее, я действительно не знаю, когда использовать какой-либо из двух... Я никогда не использовал "++ x" , и вещи всегда работали нормально до сих пор - так, когда я должен его использовать?
Пример: В цикле for, когда предпочтительнее использовать "++ x" ?
Кроме того, может ли кто-нибудь объяснить, как работают разные приращения (или декременты)? Я был бы очень признателен.
Ответы
Ответ 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
- Примечание. Множественное использование операторов приращения/уменьшения по одной переменной
в одном выражении не рекомендуется. Обработка/результаты таких
выражения варьируются от компилятора к компилятору.