Re[7]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:01
Оценка:
Здравствуйте, Bell, Вы писали:

B>Другое деле, что порядок вычисления этих аргументов не определен, но это не UB, а "unspecified behavior".


[offtopic]
UB — плохой термин, так как и "unspecified behavior" и "undefined behavior" сокращаются одинаково
[/offtopic]
Re[8]: sequence point (по мотивам инкремента)
От: Bell Россия  
Дата: 04.06.04 08:07
Оценка:
Здравствуйте, dupamid, Вы писали:

D>[offtopic]

D>UB — плохой термин, так как и "unspecified behavior" и "undefined behavior" сокращаются одинаково
D>[/offtopic]

Да, конечно.
Любите книгу — источник знаний (с) М.Горький
Re[7]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 08:11
Оценка: +2
Здравствуйте, Bell, Вы писали:

А>>>>    f(i++) + f(i++);
А>>

А>>>>Понятно, почему здесь UB?

B>>>Здесь нет UB. Можно привести аргументацию?


А>>Можно, конечно. Здесь нет точек следования, разделяющих две модификации переменной i.

А>>Можете ли Вы такие точки следования указать?
B>Могу:

B>1.9/17
B>When calling a function (whether or not the function is inline), 
B>there is a sequence point after the evaluation of all function arguments (if any) 
B>which takes place before execution of any expressions or statements in 
B>the function body...

Наличие этих точек следования никто и не отрицал. Отсюда следует, что в каждом из подвыражений
    f(i++)
побочный эффект постинкремента произойдет до входа в функцию f(). Но отсюда не следует никаких ограничений на порядок произведения побочных эффектов двух постинкрементов переменной i. В соответствии с 5/4, неопределенное поведение.
Re[7]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 08:13
Оценка:
Здравствуйте, dupamid, Вы писали:

D>Я считаю, компилятор, если у него одной переменной дважды между точками следовования приводит к каким-то проблемам, не должен оптимизировать это выражение таким образом.


Но где это требование в стандарте?
Re[5]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:14
Оценка:
Здравствуйте, Аноним, Вы писали:

D>>>>Точки следования в операторе запятая нет, но есть гарантированный порядок вычисления.


А>>>Вот это новость!..


D>>По С++'04 нет:


А>Просветите, пожалуйста, что такое С++'04. Уже принят TC2?


Это рабочий драфт Стандарта на 15 январа 2004 (есть апрельский, но его надо искать). Но ни в официально версии стандарта С++'03 ни в драфте это место не менялось с С++'89.

D>>5.18 Comma operator


А>А какова теперь редакция 1.9/18?


Редакция осталась без изменений:
1.9\18 In the evaluation of each of the expressions
a && b
a || b
a ? b : c
a , b
using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression 12).

12) The operators indicated in this paragraph are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation, and the operands form an argument list, without an implied sequence point between them.


Это слегка противоречит тому, что написано в 5.18...
Re[8]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:22
Оценка:
Здравствуйте, Аноним, Вы писали:

A>побочный эффект постинкремента произойдет до входа в функцию f(). Но отсюда не следует никаких ограничений на порядок произведения побочных эффектов двух постинкрементов переменной i. В соответствии с 5/4, неопределенное поведение.


Ну тогда и тут можно увидеть неопределенное поведение: "i++; i++;" или "i++, i++".
Re[9]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:23
Оценка:
D>Ну тогда и тут можно увидеть неопределенное поведение: "i++; i++;" или "i++, i++".

Это конечно шутка — здесь все определено!
Re[6]: sequence point (по мотивам инкремента)
От: itman itman.livejournal.com
Дата: 04.06.04 08:23
Оценка:
Господа, вы в дискуссии о разнице между UB и UB!!! отошли от самого главного, а именно от того, определен ли
порядок вызовов функции f в коде
cout<<f(i++)<<f(i++).
мне кажется, что этот код эквивалентен
( cout.operator <<(f(i++)) ).operator <<(f(i++))
Второй вызов функции f может произойти только после того, как создастся временный объект. Где здесь может возникнуть неопределенность?
В свою очередь инкремент переменной i будет происходить дважды и опять-таки после вывода f(i) в поток вывода. пардон за каламбур, но пред очередным вызовом функции.
Если я что-то неправильно написал, просьба меня поправить
Внесены исправления автора — ПК
Re[5]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 08:25
Оценка:
> несмотря на то что Павел Кузнецов утверждает, что модификация одной переменной между точками следования — есть undefined behavior, пока это не отднозначно

Давненько эта тема не поднималась... Если я правильно помню, твое мнение базировалось на наличии дефект-репорта 351. За это время комитетчики успели по нему формально проголосовать, как и ожидалось, подтвердив нормативную часть: http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351 Итого, уже без каких-либо сомнений — undefined
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: sequence point (по мотивам инкремента)
От: Аноним  
Дата: 04.06.04 08:27
Оценка:
Здравствуйте, dupamid, Вы писали:

D>Это рабочий драфт Стандарта на 15 январа 2004 (есть апрельский, но его надо искать). Но ни в официально версии стандарта С++'03 ни в драфте это место не менялось с С++'89.


В Вашей цитате было одно отличие в параграфе 1: "and is a bit-field if the right operand is an lvalue and a bit-field." Этого дополнения раньше не было.

D>Это слегка противоречит тому, что написано в 5.18...


В чем же Вы видите противоречие?
Re[7]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:31
Оценка:
Здравствуйте, itman, Вы писали:

I>Господа, вы в дискуссии о разнице между UB и UB!!! отошли от самого главного, а именно от того, определен ли

I>порядок вызовов функции f в коде
I>cout<<f(i++)<<f(i++).
I>мне кажется, что этот код эквивалентен
I>( cout.operator cout(f(i++)) ).operator cout(f(i++))

А это что за странный оператор "operator cout"

I>Второй вызов функции f может произойти только после того, как создастся временный объект. Где здесь может возникнуть неопределенность?


Какой временный объект? Выражение на самом деле такое "operator <<(operator <<(cout, f(i++)), f(i++))" причем оператор << возвращает не временный объект, а ссылку на ostraem.

I>В свою очередь инкремент переменной i будет происходить дважды и опять-таки после вывода f(i) в поток вывода. пардон за каламбур, но пред очередным вызовом функции.


Дело в том, что аргументы могут вычисляться раньше вызовова функции, что здесь и происходит, реализация вначале вычисляет все аргументы, которые может быз вызовов функций, а потом вызывает функции, и вычисляет оставшиеся.
Re: sequence point (по мотивам инкремента)
От: Кодт Россия  
Дата: 04.06.04 08:35
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Из стандарта, я понял, что вызов функции является sequence point. Если это так, объясните мне, как работает следующий фрагмент кода:


А>
А>#include <iostream>

А>int f(int i) { return i;}

А>void main()
А>{
А>    int i = 0;
А>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
А>}

А>


А>Или здесь UB? Почему?


Вызов функции является sequence point. А вот вычисление аргумента для функции — нет
Поэтому undefined.

Если бы ты сделал автоинкремент изолированным:
int predinc(int& i) { return ++i; }
int postinc(int& i) { return i++; }

....
А>    std::cout << f(i) << " " << f(postinc(i)) << " " << f(predinc(i)) << " " << f(postinc(i)) << std::endl;
....

то получил бы менее тяжкое, unspecified behaviour.
Перекуём баги на фичи!
Re[7]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 08:37
Оценка:
> определен ли порядок вызовов функции f в коде
> cout<<f(i++)<<f(i++).
> мне кажется, что этот код эквивалентен
> ( cout.operator <<(f(i++)) ).operator <<(f(i++))
> Второй вызов функции f может произойти только после того, как создастся временный объект. Где здесь может возникнуть неопределенность?

Вне зависимости от порядка вызовов функции, ее аргументы могут вычисляться в разной последовательности, а — теоретически — даже и одновременно. Т.е. компилятор может сначала вычислить аргументы всех вызовов в одном выражении, а уж потом вызывать функции. Т.е. как минимум в одной возможной последовательности вычисления выражения, между двумя модификациями одного скалярного объекта нет точки следования. Согласно стандарту это приводит к неопределенному поведению.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 08:40
Оценка:
> точка следования — это когда все побочные эффекты предыдущего выражения уже сработали, а следующего — еще не начались.
> Для оператора запятая гарантируется только первое.

И второе тоже: побочные эффекты выражения не могут начаться раньше его вычисления
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[8]: sequence point (по мотивам инкремента)
От: itman itman.livejournal.com
Дата: 04.06.04 08:41
Оценка:
D>А это что за странный оператор "operator cout"

см. пост выше я исправил

I>>Второй вызов функции f может произойти только после того, как создастся временный объект. Где здесь может возникнуть неопределенность?


D>Какой временный объект? Выражение на самом деле такое "operator <<(operator <<(cout, f(i++)), f(i++))" причем оператор << возвращает не временный объект, а ссылку на ostraem.


ага, ну я понял свою ошибку, спасибо. да так действительно UB или UB, поскольку порядок вычисления аргументов не гарантирован.

I>>В свою очередь инкремент переменной i будет происходить дважды и опять-таки после вывода f(i) в поток вывода. пардон за каламбур, но пред очередным вызовом функции.


D>Дело в том, что аргументы могут вычисляться раньше вызовова функции, что здесь и происходит, реализация вначале вычисляет все аргументы, которые может быз вызовов функций, а потом вызывает функции, и вычисляет оставшиеся.
Re[8]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 04.06.04 08:49
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Вне зависимости от порядка вызовов функции, ее аргументы могут вычисляться в разной последовательности, а — теоретически — даже и одновременно.


Почему же теортетически: на архитектурах с явным параллелизмом на уровне инструкций (например Itanium) так и есть.

ПК> Т.е. компилятор может сначала вычислить аргументы всех вызовов в одном выражении, а уж потом вызывать функции. Т.е. как минимум в одной возможной последовательности вычисления выражения, между двумя модификациями одного скалярного объекта нет точки следования. Согласно стандарту это приводит к неопределенному поведению.


Собственно вопрос именно в этом и есть: где написано, что если есть хотя одна такая последовательность, то компилятор может выбрать именно ее. В случае когда есть последовательности с точками следования, в которых таких проблем нет. Т.е. что компилятор может выносить вычисления за точки следования. Я считаю, что он может все перемещать только в пределех между двумя точками следования, но ни в коем случае за их пределеами. Т.е. точки следования ставят барьеры в пределеах которых, можно тасовать вычисления как компилятор захочет, пока не нарушаются зависимости по данным.
Re[2]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 08:52
Оценка: 3 (1)
> А>
> А>    std::cout << f(i) << " " << f(i++) << " " << f(++i) << " " << f(i++) << std::endl;
> А>

>
> А>Или здесь UB? Почему?
>
> В таком случае стандарт не гарантирует именно ту последовательность вызовов функции f(), в которой ты написал. Порядок вызовов произволен.

Главное не в порядке вызовов функции, а в порядке вычисления аргументов — а вот он-то и не задан. Т.е. скалярный объект i может модифицироваться без наличия между модификациями точки следования — неопределенное поведение.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: sequence point (по мотивам инкремента)
От: jazzer Россия Skype: enerjazzer
Дата: 04.06.04 08:58
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> точка следования — это когда все побочные эффекты предыдущего выражения уже сработали, а следующего — еще не начались.

>> Для оператора запятая гарантируется только первое.

ПК>И второе тоже: побочные эффекты выражения не могут начаться раньше его вычисления :-)


А есть ли в Стандарте такое требование? ;)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 09:11
Оценка:
> ПК>Вне зависимости от порядка вызовов функции, ее аргументы могут вычисляться в разной последовательности, а — теоретически — даже и одновременно.
>
> Почему же теортетически: на архитектурах с явным параллелизмом на уровне инструкций (например Itanium) так и есть.

Теоретически потому что я не видел компилятора, использующего эту возможность.

> Собственно вопрос именно в этом и есть: где написано, что если есть хотя одна такая последовательность, то компилятор может выбрать именно ее.


Дело в обратном: нигде нет требования, чтобы он ее не выбирал.

> Я считаю, что он может все перемещать только в пределех между двумя точками следования, но ни в коем случае за их пределеами. Т.е. точки следования ставят барьеры в пределеах которых, можно тасовать вычисления как компилятор захочет, пока не нарушаются зависимости по данным.


Точки следования не определяют порядок вычисления, они только отделяют применение побочных эффектов одних вычислений от других. Когда компилятор выберет порядок вычислений, в дело вступят точки следования, предписывая компилятору места, не позднее которых побочные эффекты должны быть применены. Т.е. если есть выражение:
f(++i) + f(++i)

то стандарт не требует от компилятора вычислять аргументы вызовов непосредственно перед самими вызовами. Т.е. вполне допустимыми последовательностями вычислений, например, являются:
1) вычислить аргумент первого вызова, вызвать первую функцию, вычислить аргумент второго вызова, вызвать вторую функцию;
2) вычислить аргумент второго вызова, вызвать вторую функцию, вычислить аргумент первого вызова, вызвать первую функцию;
3) вычислить аргумент первого вызова, вычислить аргумент второго вызова, вызвать первую функцию, вызвать вторую функцию;
4) вычислить аргумент первого вызова, вычислить аргумент второго вызова, вызвать вторую функцию, вызвать первую функцию.

В последних двух случаях между вычислением аргументов точек следования нет.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 04.06.04 09:19
Оценка:
> ПК>И второе тоже: побочные эффекты выражения не могут начаться раньше его вычисления
>
> А есть ли в Стандарте такое требование?

Это уже машина времени какая-то получается
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.