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