U>по теме: кто-нибудь можно четко ответить на поставленный вопрос? U>тут уже дали намек на то, что это как-то связано с грамматикой языка U>подробнее можно осветить это?
с грамматикой связан пример в исходном вопросе: выражение ++i++ означает для компилятора ++ (i++), для типа int такое выражение содержит ошибку — попытка применить префиксный ++ к r-value типа int.
Со скобками выражение парсится как надо, но тут уже многократное изменение переменной между двумя точками следования
Of course, the code must be complete enough to compile and link.
Здравствуйте, Masterkent, Вы писали:
R>>Не вижу ссылки на "хорошую". M>Хороших статей по данному вопросу не знаю.
IMHO, ты можешь попробовать её написать, раз уж всё так нереально запущено в этом деле
Тут же не только форум, но и вики и журнал есть
M>Сомнительна польза от прочтения статей, где авторы описывают своё смутное понимание некоего предмета. IMO, чтобы писать статьи, надо обладать определённым багажом знаний, а не одними благими намерениями поучить других.
Ну они хотя бы как-то пытаются помочь, а от "просто критики" ещё меньше пользы тем, кто не разобрался ещё с точками следования...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop:
M>>Хороших статей по данному вопросу не знаю.
E>IMHO, ты можешь попробовать её написать, раз уж всё так нереально запущено в этом деле
А есть ли смысл? Концепция упорядочивания вычислений в C++0x более совершенна как плане интуитивной понятности, так и в плане отсутствия некоторых явно ненужных ограничений. В частности,
int i = 0;
(++i)++;
это вполне well-defined код в рамках C++0x.
1.9 Program execution — p. 15:
The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
5.3 Unary expressions -> 5.3.2 Increment and decrement:
If x is not of type bool, the expression ++x is equivalent to x+=1
5.17 Assignment and compound assignment operators:
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
5.2 Postfix expressions -> 5.2.6 Increment and decrement:
The value computation of the ++ expression is sequenced before the modification of the operand object.
Согласно этим правилам, порядок вычислений должен быть следующим:
1) вычисление значения операнда префиксного ++,
2) модификация объекта, осуществляемая префиксным ++,
3) вычисление значения результата префиксного ++ — оно же вычисление значения операнда постфиксного ++,
4) вычисление значения результата постфиксного ++,
5) модификация объекта, осуществляемая постфиксным ++.
Под
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined
данная последовательность вычислений, очевидно, не подпадает.
Такой код
(n *= 10) += decimal_digit; // n и decimal_digit обозначают скалярные объекты
C++03 совершенно необоснованно определяет как влекущий undefined behavior (по сути это не более чем издержки не вполне рационального обобщения в правилах).
На данный момент мне гораздо интереснее изучать C++0x и сообщать о найденных ошибках и недочётах комитету по стандартизации C++, чем работать над мало кому нужной подробной статьёй по каким-то точкам следования.
M>>Сомнительна польза от прочтения статей, где авторы описывают своё смутное понимание некоего предмета. IMO, чтобы писать статьи, надо обладать определённым багажом знаний, а не одними благими намерениями поучить других. E>Ну они хотя бы как-то пытаются помочь
Пытаясь "как-то" помочь, можно ненароком оказать медвежью услугу. Я такое уже не раз наблюдал.
E>а от "просто критики" ещё меньше пользы тем, кто не разобрался ещё с точками следования...
А это уже не тебе решать. Я тоже далеко не во всех областях разбираюсь, и если при изучении чего-то некто будет помогать мне фильтровать вот такие писульки, я буду только рад. Я заинтересован в получении только достоверной и не сбивающей с толку информации.
Привет всем!
У меня возник вопрос — почему-то VS мне на попытку скомпилить такой код:
int i = 10;
++i++;
выдает сообщение об ошибке:
error C2105: '++' needs l-value
Вопрос в том, ПОЧЕМУ?
Я знаю, что
префиксный ++ принимает l-value и возвращает l-value
постфиксный ++ принимает l-value и возвращает r-value
Так получается, что компилятор считает, что первым выполняется постфиксный, получается... Так что ли? Откуда еще могло взяться r-value?
НО! Я то думала, что первым должен выполниться префиксный. Кстати, вот здесь есть приоритет операций, где префиксный ++ стоит вообще первым по приоритету, а постфиксный — последним.
Может мне кто-нить объяснить, что за хрень в этом выражении происходит?
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, uzhas, Вы писали:
L_L>>>>>>нехороший пример, демонстрирует неопределенное поведение. V>>>>>Это вы про reinterpret_cast? L_L>>>>это я про то, про что я. фрагмент "кода" был приведен. V>>>Так там скобки разграничивают expression'ы. U>>не путайте с sequence points V>Ну а чем таки это отличается от этого: V>
V>(a+b)*(a-b);
V>
V>А то получается в сложении/умножении скобки работают, а здесь нет. V>И как в таком случае вот это будет работать: V>
V>(a+b)++;
V>
V>?
Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Erop, Вы писали:
V>>Но как инкремент может выполниться раньше, если неизвестно что инкрементить? E>Как так "не известно"? Переменную i, конечно же...
Ты код смотрел?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Lorenzo_LAMAS, Вы писали:
V>>Нет. Есть возражения по однозначности анализа, приведённого здесь, что якобы приведённое выражение: V>>
V>>int i = 0;
V>>(++i)++;
V>>
V>>однозначно неопределёное, что как получается ещё не факт. L_L>из чего следует, что не факт? я пропустил многомудрые коды, обоснование твоего утверждения в них?
Ну если оператор перегружен (а мы этого не знаем).
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
L_L>нехороший пример, демонстрирует неопределенное поведение.
поясни что неопределенного?
для меня все определено:
если i = 10, то сначала (++i) т.е. i=11, потом i++, т.е. i=12.
а асэбмлерный листинг это подтверждает
On 18.11.2010 15:25, XJess wrote:
> Так получается, что компилятор считает, что первым выполняется постфиксный, > получается... Так что ли? Откуда еще могло взяться r-value? > > НО! Я то думала, что первым должен выполниться префиксный. Кстати, вот > http://do.rksi.ru/library/courses/demo/tema1_3.dbk <здесь> есть приоритет > операций, где префиксный ++ стоит вообще первым по приоритету, а постфиксный — > последним.
Как приоритет операций связан с порядком выполнения этих операций ?
(вопрос риторический, отвечать надо только себе самому).
> > Может мне кто-нить объяснить, что за хрень в этом выражении происходит?
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>>нехороший пример, демонстрирует неопределенное поведение. V>>Это вы про reinterpret_cast? L_L>это я про то, про что я. фрагмент "кода" был приведен.
Так там скобки разграничивают expression'ы.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>>>>нехороший пример, демонстрирует неопределенное поведение. V>>>Это вы про reinterpret_cast? L_L>>это я про то, про что я. фрагмент "кода" был приведен. V>Так там скобки разграничивают expression'ы.
не путайте с sequence points
по теме: кто-нибудь можно четко ответить на поставленный вопрос?
тут уже дали намек на то, что это как-то связано с грамматикой языка
подробнее можно осветить это?
Здравствуйте, uzhas, Вы писали:
L_L>>>>>нехороший пример, демонстрирует неопределенное поведение. V>>>>Это вы про reinterpret_cast? L_L>>>это я про то, про что я. фрагмент "кода" был приведен. V>>Так там скобки разграничивают expression'ы. U>не путайте с sequence points
Ну а чем таки это отличается от этого:
(a+b)*(a-b);
А то получается в сложении/умножении скобки работают, а здесь нет.
И как в таком случае вот это будет работать:
(a+b)++;
?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, rg45, Вы писали:
L_L>>>>>>>нехороший пример, демонстрирует неопределенное поведение. V>>>>>>Это вы про reinterpret_cast? L_L>>>>>это я про то, про что я. фрагмент "кода" был приведен. V>>>>Так там скобки разграничивают expression'ы. U>>>не путайте с sequence points V>>Ну а чем таки это отличается от этого: V>>
V>>(a+b)*(a-b);
V>>
V>>А то получается в сложении/умножении скобки работают, а здесь нет. V>>И как в таком случае вот это будет работать: V>>
V>>(a+b)++;
V>>
V>>? R>Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет.
Ну так скобки вводят точки следования или нет?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>>Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет. V>>Ну так скобки вводят точки следования или нет? L_L>нет
Ok.
Тогда в этом случае инкремент может выполниться раньше?
struct A
{
int a;
A(const A& a)
{
this->a = a.a;
}
A(int i = 0)
{
a = i;
}
A& operator +(A& b)
{
if(a >= b.a)
{
a += b.a;
return *this;
}
b.a += a;
return b;
}
A operator ++(int)
{
A r = *this;
a++;
return r;
}
};
int main()
{
A a(10);
A b(11);
(a+b)++;
return 0;
}
Но как инкремент может выполниться раньше, если неизвестно что инкрементить?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Но как инкремент может выполниться раньше, если неизвестно что инкрементить?
Как так "не известно"? Переменную i, конечно же...
Вот представь себе суперпараллельную архитектуру, где можно запустить оба инкремента параллельно. Там оба ++ запустятся, прибавят и оба запишут увеличенное значение обратно. Не факт, что обратно запишути +1, а не +2...
Во всяком случае стандарт это как бы разрешат. Осталось найти такие компилятор и аппаратуру, которые этим разрешением в этом конкретном случае пользуются. Я таких пока не видел, например..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>>>Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет. V>>>Ну так скобки вводят точки следования или нет? L_L>>нет V>Ok. V>Тогда в этом случае инкремент может выполниться раньше? V>
V>struct A
V>{
V> int a;
V> A(const A& a)
V> {
this->>a = a.a;
V> }
V> A(int i = 0)
V> {
V> a = i;
V> }
V> A& operator +(A& b)
V> {
V> if(a >= b.a)
V> {
V> a += b.a;
V> return *this;
V> }
V> b.a += a;
V> return b;
V> }
V> A operator ++(int)
V> {
V> A r = *this;
V> a++;
V> return r;
V> }
V>};
V>int main()
V>{
V> A a(10);
V> A b(11);
V> (a+b)++;
V> return 0;
V>}
V>
V>Но как инкремент может выполниться раньше, если неизвестно что инкрементить?
Вход в функцию — это sequence point.
operator++ — это функция с 1 аргументом.
In C and C++, sequence points occur in the following places. (In C++, overloaded operators act like functions, and thus operators that have been overloaded introduce sequence points in the same way as function calls.)
...
Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
V>>Но как инкремент может выполниться раньше, если неизвестно что инкрементить? B>Вход в функцию — это sequence point. B>operator++ — это функция с 1 аргументом. B>
B>In C and C++, sequence points occur in the following places. (In C++, overloaded operators act like functions, and thus operators that have been overloaded introduce sequence points in the same way as function calls.)
B>...
B>Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
Ты будешь смеятся, но переопределение, к примеру, операторов || и && добавляет UB, а не удаляет его.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, blackhearted, Вы писали:
V>>>Но как инкремент может выполниться раньше, если неизвестно что инкрементить? B>>Вход в функцию — это sequence point. B>>operator++ — это функция с 1 аргументом. B>>
B>>In C and C++, sequence points occur in the following places. (In C++, overloaded operators act like functions, and thus operators that have been overloaded introduce sequence points in the same way as function calls.)
B>>...
B>>Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
V>Ты будешь смеятся, но переопределение, к примеру, операторов || и && добавляет UB, а не удаляет его.
Я отвечал на конкретный вопрос. По поводу того, где в коде
(a+b)++;
sequence point.
По ответу возражения есть?
|| и && сами по себе являются точками следования.
Не подскажешь, где в стандарте сказано про то, что user-defined версии этих операторов вносят UB?
Здравствуйте, blackhearted, Вы писали:
V>>Ты будешь смеятся, но переопределение, к примеру, операторов || и && добавляет UB, а не удаляет его. B>Я отвечал на конкретный вопрос. По поводу того, где в коде B>
B>(a+b)++;
B>
B>sequence point. B>По ответу возражения есть?
Нет. Есть возражения по однозначности анализа, приведённого здесь, что якобы приведённое выражение:
int i = 0;
(++i)++;
однозначно неопределёное, что как получается ещё не факт.
B>|| и && сами по себе являются точками следования. B>Не подскажешь, где в стандарте сказано про то, что user-defined версии этих операторов вносят UB?
Не подскажу, нету под рукой, да и занят я другим.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, blackhearted, Вы писали:
V>>>Ты будешь смеятся, но переопределение, к примеру, операторов || и && добавляет UB, а не удаляет его. B>>Я отвечал на конкретный вопрос. По поводу того, где в коде B>>
B>>(a+b)++;
B>>
B>>sequence point. B>>По ответу возражения есть? V>Нет. Есть возражения по однозначности анализа, приведённого здесь, что якобы приведённое выражение: V>
V>int i = 0;
V>(++i)++;
V>
V>однозначно неопределёное, что как получается ещё не факт.
ИМХО, тоже не всегда неопределено. Но так как не извесно окружение этого кода сказать точно нельзя.
В реальности компилятор имеет в момент разбора этой конструкции вю необходимую информацию и должен вести себя в соответствии со стандартом.
rg45:
R>Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет.
Плохая статья.
"Точки следования (sequence points) — это некие точки в программе, где состояние реальной программы полностью соответствует состоянию абстрактной машины, описанной в Стандарте"
Это бред. Состояние реальной программы должно так или иначе обеспечивать допустимое observable behavior и, за исключением этого аспекта, оно полностью определяется реализацией. Точки следования нужны только для формального определения этого самого observable behavior.
"В каждой точке следования все побочные эффекты кода, который уже выполнен, уже случились, а побочные эффекты для кода, который еще не был выполнен, еще не случились."
Здесь и далее по тексту автор не уточняет, что речь идёт об абстрактной машине. Тем, кому адресована данная статья, это, скорее всего, не очевидно, и у благодарных читателей может сложиться неверное представление о том, как работает данная модель. Для кода
int x;
x = 3;
cout << x << endl;
x = 4;
компилятор может сгенерировать такой же исполнительный код, как и для
int x;
x = 4;
cout << 3 << endl;
Вывод действительно должен быть тройкой с переносом, но не потому, что компилятор должен в точности обеспечивать последовательность вычислений, заданную программистом, а потому, что это единственный вывод, который мог бы получиться на абстрактной машине (которая обеспечивает исходный порядок вычислений).
"Интересный момент с таким кодом:
int a=1, b=2, c=3;
a=b=c=0;
Стандарт как-то очень нечетко описывает такую ситуацию. Он говорит, что операция должна происходить справа налево, но ничего не говорит дополнительно по поводу того, когда должен быть результат этой операции записан в переменную."
Стандарты C и C++ исчерпывающе описывают данную ситуацию:
С99:
An assignment expression has the value of the left operand after the assignment
C++98, C++03:
The result of the assignment operation is the value stored in the left operand after the assignment has taken place"
V>>>>однозначно неопределёное, что как получается ещё не факт. V>>Ну если оператор перегружен (а мы этого не знаем). L_L> ну блин, ну вот конкретный-то пример с целым что уж тут
Конкретный пример с интом однозначен. Так это, вы посмотрите на автора топика, ему наверняка непонятен не только этот пример.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Masterkent, Вы писали:
R>>Прочти о том, что такое точки следования, и большинство твоих вопросов отпадет.
M>Плохая статья.
Не вижу ссылки на "хорошую".
M>...
Основная цель этой статьи — объяснить "на пальцах" начинающим программистам что такое точки следования так, чтоб дошло до ума и сердца. И статья эту цель достигает. И даже не смотря на справедливость твоих замечаний, ИМХО, их ценность в данном конкретном случае сомнительна.
--
Справедливость выше закона. А человечность выше справедливости.
M>>C++98, C++03: M>>The result of the assignment operation is the value stored in the left operand after the assignment has taken place"
L_L>если мне не изменяет память, то комитет обсуждал последний случай на предмет UB (для C++03/C++98)?
да, было такое в issue 222:
One could argue that as the C++ standard currently stands, the effect of x = y = 0; is undefined. The reason is that it both fetches and stores the value of y, and does not fetch the value of y in order to compute its new value.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Vain, Вы писали:
V>Ты код смотрел?
В твоём коде всё однозначно, однако. Вход/выход в/из функции -- точка следования, так что UB нет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, blackhearted, Вы писали:
B>|| и && сами по себе являются точками следования. B>Не подскажешь, где в стандарте сказано про то, что user-defined версии этих операторов вносят UB?
Видимо имеются вариации на тему
if( myNumber && 1/myNumber < 5 ) {
}
если myNumber -- это какое-то моё число, например с фиксированной точкой, и у него переопределить &&, то может выйти а-та-та....
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
rg45:
M>>Плохая статья.
R>Не вижу ссылки на "хорошую".
Хороших статей по данному вопросу не знаю.
R>Основная цель этой статьи — объяснить "на пальцах" начинающим программистам что такое точки следования так, чтоб дошло до ума и сердца. И статья эту цель достигает.
По поводу того, что такое точки следования, объяснение в корне неправильное. Как именно точки следования связаны с оптимизацией, не объясняется (упомянутое в статье переупорядочивание инструкций не имеет прямого отношения к причинам появления точек следования как детали формализации observable behavior). Множество ситуаций, когда чтение и запись не разделены точками следования, рассматривается лишь частично, да и то неправильно.
Единственное что оттуда можно почерпнуть — это то, что две модификации одной скалярной переменной, не разделённые точкой следования, влекут наличие в программе неопределённого поведения. Но это и без статьи тут многие знают (и могут об этом рассказать).
R>И даже не смотря на справедливость твоих замечаний, ИМХО, их ценность в данном конкретном случае сомнительна.
Сомнительна польза от прочтения статей, где авторы описывают своё смутное понимание некоего предмета. IMO, чтобы писать статьи, надо обладать определённым багажом знаний, а не одними благими намерениями поучить других.
L_L>One could argue that as the C++ standard currently stands, the effect of x = y = 0; is undefined. The reason is that it both fetches and stores the value of y, and does not fetch the value of y in order to compute its new value.
Эта reason — отсыл в никуда. В стандарте сказано:
Furthermore, the prior value shall be accessed only to determine the value to be stored.
"value stored in the left operand after the assignment has taken place" — это явно не prior value. Хотя формулировка с "prior value" не самая удачная (значение лишь потенциально предыдущее), намерение комитета прослеживается вполне чётко.
void f(int &i)
{
int j;
j = i = 0; // well-defined
j = i + (i = 1); // undefined behavior
}
Единственное, что для меня остаётся неясным в данном примере, это как реализация может трактовать данное undefined behavior, а если конкретно — имеет ли она право выдавать ошибку и не завершать трансляцию программы вообще, если f в программе потенциально может не вызываться.
Здравствуйте, XJess, Вы писали: XJ>int i = 10; XJ>++i++; XJ>error C2105: '++' needs l-value XJ>Вопрос в том, ПОЧЕМУ?
А ЧЕГО СОБСТВЕННО ВЫ ХОТЕЛИ ОТ ЭТОГО КОДА?
моё мнение: и правильно сделал компилятор что ругнулся,
да есть инкременты, но использовать их надо с умом, например:
int nI=0;
myFunc (++nI, nI--){
...
}
// илиwhile ( --nI ) {
...
} // или ...
то здесь у меня вопросов нет, и у компилятора надеюсь тоже,
а если мне надо увелитчить целое на 2, то я пишу
int nI=0;
nI += 2;
// или
nI = nI + 2;
// ну а если условие только с использованием инкрементов
nI++;
nI++;
//я бы даже не написал
(++nI)++;
//т.к. со скобками и в скобках все понятно, а вот код
()++;
// через некоторе время или другим компилятором может "дать течь"
и заметте не парюсь по пустякам.
ЗАЧЕМ САМИМ СЕБЕ СОЗДАВАТЬ ПРОБЛЕМЫ?
компиляторы как и стандарты пишут люди, ОБЫЧНЫЕ люди, и стандарты (как и компиляторы) со временем изменяются.
Я за стабильно работающий код всегда.
в каждом проекте всегда есть над чем поработать, более серьезное и существенное.....
Здравствуйте, blackhearted, Вы писали:
V>>int i = 0; V>>(++i)++; V>>[/ccode]
B>ИМХО, тоже не всегда неопределено. Но так как не извесно окружение этого кода сказать точно нельзя. B>В реальности компилятор имеет в момент разбора этой конструкции вю необходимую информацию и должен вести себя в соответствии со стандартом.
Вы можете мне такой темной привести пример, как окружение может вызвать неоднозначность в этом коде? Я этого решительно пока не знаю.