--x++
Верно ли утверждать, что (--x)++
представляет собой некоторый эквивалент (x-1)
? Т. е. верно ли, что этот код корректен и НЕ порождает неопределённое поведение?
Почему приходится ставить скобки вокруг декремента? Я ожидал, что без скобок компилятор в конструкции --x++
сначала возьмёт префиксную операцию, а потом постфиксную, но по какой-то причине он делает наоборот:
error: lvalue required as decrement operand
cout << --x++ << endl;
^~
Является ли такое поведение компилятора верным?
#include <iostream>
using namespace std;
int main()
{
int x = 8;
cout << (--x)++ << endl;
cout << x << endl;
return 0;
}
По определению, выражение (--x)++
ведет себя как (x = x - 1)++
. Начиная с С++17 процесс вычисления оператора присваивания упорядочен (sequenced) очень строго: правая часть полностью упорядочена перед левой частью и сам акт присваивания упорядочен перед вычислением результата оператора присваивания.
То есть процесс вычисления оператора присваивания a = b
в С++17 разделили на изолированные друг от друга "отсеки" [[a] = [b]]
, обрабатываемые справа-налево
Сначала вычисляется значение b
и выполняются все побочные эффекты, присутствующие в b
Затем вычисляется значение a
и выполняются все побочные эффекты, присутствующие в a
Затем происходит собственно присваивание
И только после этого результат выражения a = b
возвращается в контекст более высокого уровня
Это означает, что случае (--x)++
неопределенного поведения нет. Все побочные эффекты и чтения значений строго упорядочены относительно друг друга. Это выражение не меняет значения x
, а его результат - это исходное значение x
минус 1
.
В С++14 и ранее ситуация могла быть иной... Например, до C++17 выражение i = i++
порождало неопределенное поведение, а начиная с C++17 поведение этого выражения уже полностью определено. Однако в вашем конкретном примере все в порядке и в С++11. Формально в С++98 поведение не определено, но даже это признано дефектом стандарта С++98.
При этом стоит заметить, что несмотря на довольно строгую упорядоченность, которую С++17 внес в процесс вычисления индивидуального оператора присваивания, вышеупомянутые "отсеки" не гарантируют изолированности процессов вычисления нескольких независимых операторов присваивания друг от друга. Выражение (i = 1) + (i = 2)
по-прежнему порождает неопределенное поведение, потому что побочный эффект i = 1
не упорядочен относительно побочного эффекта i = 2
.
В С и С++ во все века и времена постфиксные операторы имели больший приоритет, чем префиксные. Поэтому мне не ясно, почему вы ожидали, что --x++
может быть корректным выражением.
Увидев оператор --
компилятор ожидает обьект, а так как x++
возвращает временный обьект, то эта операция становится не действительным. Со скобкой эта проблема отпадает: сначала значение обьекта уменьшается, а потом для этого же обьекта выполняется оператор ++
По поводу первого вопроса: не вижу ничего некорректного и нет причин для неопределенного поведения... P.S. Неопределенное поведение в таких выражениях как --x + x--
из за того, что стандарт не определяет порядок вычисления операндов(что сначала вычислять --x
или x--
? ) В случаи в вопросе, этой проблемы нет.
Будет неопредленное поведение, у вас два изменения в одной точке следования. Скобки точку не создают.
1) Приоритет операций: http://cppstudio.com/post/302/ сначала постфиксный, потом префиксный. 2) Постфиксный инкремент возвращает ссылку на временный объект (rvalue), а префиксный декремент принимает ссылку только на постоянный объект (lvalue). 3) Неопределённого поведения здесь порождать нечему. --x возвращает lvalue (ссылку на х), (--x)++ возвращает rvalue - (копию (--x)) + 1. Операция вывода с rvalue объектами работает. Более того, если включить оптимизацию, он этот код заменит прямо на х-1:
int square(int num) {
return (--num)++;
}
gcc9.1 -O2
leal -1(%rdi), %eax
ret
https://godbolt.org/z/rq1uA-
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть два DataGridViewВ одном главные записи, во втором детали по нему
Подскажите, как можно реализовать коллекцию, реализующую INotifyCollectionChanged, и которую можно было бы потокобезопасно перебирать? Наследоваться...
прошу Вас помогите 3 дня уже почти сижу не могу понять как сделатьЕсть ХМЛ документ вот пример: Как видите, тут два атрибута <"ValType Type="> повторяются,...