Увеличение в C++. Когда использовать x++ или ++x?
-
06-07-2019 - |
Вопрос
В настоящее время я изучаю 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
- Примечание:Множественное использование операторов приращения/уменьшения по той же переменной в одном выражении не рекомендуется.Обработка/результаты таких
выражения варьируются от компилятора к компилятору.