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