Re: a = a++; каков результат?
От: Fwiffo Россия  
Дата: 29.04.09 17:09
Оценка: 1 (1) +4
Здравствуйте, ajanov, Вы писали:

A>Все доброго сремени суток!


A>Сегодня у новичка увидел в коде:



A>
A>a = a++;
A>



A>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


Это что за правила такие?
Переменная модифицируется два раза между точками следования, так что результат может быть какой угодно.
Undefined behavior и есть.
Re[2]: a = a++; каков результат?
От: leo_jan Армения  
Дата: 29.04.09 18:44
Оценка: -5
Здравствуйте, Fwiffo, Вы писали:

F>Здравствуйте, ajanov, Вы писали:


A>>Все доброго сремени суток!


A>>Сегодня у новичка увидел в коде:



A>>
A>>a = a++;
A>>



A>>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


F>Это что за правила такие?

F>Переменная модифицируется два раза между точками следования, так что результат может быть какой угодно.
F>Undefined behavior и есть.

Это правило последовательности выполнения операторов, а последовательность такова:
1) создается временный объект которому приписывается значение 'a'
2) значение а увеличивается на 1
3) а приписывается приписывается значение временного объекта — то есть начальное значение 'а'

Друго дело что писать a = a++; — дурной тон
Re[3]: a = a++; каков результат?
От: Alexey F  
Дата: 29.04.09 18:56
Оценка: +5
Здравствуйте, leo_jan, Вы писали:

_>Это правило последовательности выполнения операторов, а последовательность такова:

Ничего подобного Это — undefined behavior, ни порядок выполнения, ни последовательность действий при таком раскладе не определены. Компилятор может вписать вместо этого вызов "format D:". И будет прав...

_>Друго дело что писать a = a++; — дурной тон

Это не дурной тон, это — неопределённое поведение.
Re[3]: a = a++; каков результат?
От: BigBoss  
Дата: 08.05.09 23:59
Оценка: 1 (1) +1 -1 :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, BigBoss, Вы писали:


BB>>operator= (a, a++);

BB>>А где в стандарте С++ описан порядок вычисления аргументов???

E>Это тут не при чём, так как (если закрыть глаза на то, что так нельзя) первый аргумент -- это ссылка на a, а второй -- число. Так что тут от порядка ничего зависеть не будет. Ну а вызов функции -- это таки точка следования...

E>Но a тут -- стандартный тип, так что никакого operator = тут нет, и точки следования нет и всё такое...

видимо я что-то пропустил, откуда видно, что a -- это стандартный тип? И что это такое вообще "стандартный тип"?
Re[3]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 29.04.09 19:02
Оценка: +3
Здравствуйте, leo_jan, Вы писали:

A>>>
A>>>a = a++;
A>>>



A>>>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


F>>Это что за правила такие?

F>>Переменная модифицируется два раза между точками следования, так что результат может быть какой угодно.
F>>Undefined behavior и есть.

_>Это правило последовательности выполнения операторов, а последовательность такова:

_>1) создается временный объект которому приписывается значение 'a'
_>2) значение а увеличивается на 1
_>3) а приписывается приписывается значение временного объекта — то есть начальное значение 'а'

_>Друго дело что писать a = a++; — дурной тон


Нет, никакой такой последователmности, не говоря уже о каких-то подобных "правилах", здесь нет.

В языках С и С++ выражение 'a = a++;' имеет следующую семантику

1. a++: Взять старое значение 'a', вернуть его в качестве результата и запланировать выполнение побочного эффекта 1: "поместить в 'a' значение А равное старому значению плюс 1"
2. a = (1): Взять возвращенное шагом (1) значение, вернуть его в качесте результата и запланировать выполнение побочного эффекта 2: "поместить в 'a' значение B, полученное с шага (1), т.е. фактически старое значение 'a'"
3. Полное выражение, точка следования: Викинуть нафиг возвращенное шагом (2) значение, выполнить все запланированные к данному моменту побочные эффекты в любом порядке.

Проблема возникает на шаге 3 потому, что к этому моменту у нас запланировано 2 побочных эффекта и финальное значение 'a' зависит от порядка их выполнения.
Best regards,
Андрей Тарасевич
Re[5]: a = a++; каков результат?
От: Masterkent  
Дата: 10.05.09 14:25
Оценка: 14 (2)
Здравствуйте, elcste, Вы писали:

i = 1; i = foo ( i++ );

E>Относительно побочного эффекта постинкремента мы знаем, что он должен выполниться до точки следования перед входом в функцию. Но для присваивания ограничение только одно: до конца полного выражения. И хотя здравый смысл подсказывает, что это может произойти только после выхода из функции, буква стандарта никак это не подтверждает.

Буква стандарта много чего не подтверждает. Полагаться на здравый смысл всё равно приходится.

std::string f()
{
    {
        std::string s = "text";
        return s;
    }
}

Попробуй-ка найти в стандарте подтверждение тому, что выход управления из scope с объявлением s и сопутствующее ему уничтожение объекта s не может произойти до того, как будет произведена попытка скопировать значение s во временный объект, создаваемый в контексте возврата.

E>Чтобы это рассуждение стало нагляднее, представьте себе гипотетическую реализацию, в которой присваивание не атомарно. Например, перед тем, как записать значение в ячейку памяти, ее необходимо очистить влажной тряпочкой.


Абстрактную машину и реализацию следует рассматривать отдельно. Понятие точек следования служит только в целях формализации работы абстрактной машины. Эмулируя одно из возможных наблюдаемых поведений абстрактной машины, реализация не обязана копировать или эмулировать структуру самой абстрактной машины и тем более подчиняться правилам, сформулированным в отношении точек следования (1.9). Для абстрактной машины присваивание определяется следующим образом (5.17/2):

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

Очевидно, такая замена значения не может состояться до того, как будет получен объект, являющийся результатом вычисления правого операнда (нет возвращаемого функцией объекта — нет и значения выражения). Каких-то дополнительных действий, кроме осуществления данной замены, стандарт в отношении абстрактной машины, насколько я знаю, не предусматривает. Таким образом, мы получаем, что на абстрактной машине значение правого операнда формируется после точки следования, которая отделяет дальнейшее присваивание от предшествующего инкремента.

При ином раскладе вычисление подобного выражения может прекратиться до присваивания:

int g(int x);

void f(int &i)
{
    i = g(i++); // may throw
}

Если функция g сгенерирует исключение, то результирующий объект для выражения g(i++) попросту не будет создан, а потому не будет и значения, которым можно было бы заменить значение левого операнда. Разрешения каким-либо образом портить i в таком случае я в стандарте не встречал.

Каким образом реализация будет эмулировать одно из допустимых observable behavior абстрактной машины — это уже проблемы реализации. В случае

#include <iostream>

int foo (int x) { return x; }

int main()
{
    int i = 1;
    i = foo(i++);
    std::cout << i << std::endl;
}

вывод должен быть строго "1".
Re[5]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 30.04.09 06:23
Оценка: 7 (2)
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Undefined. Именно undefined.


I>Вот пример с комментарием из стандарта:


В примере — опечатка, которая уже давным-давно обнаружена, рассмотрена, исправлена и закрыта

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351

В тексте же перед примером ясно сказано, что поведение не определено (undefined)
Best regards,
Андрей Тарасевич
Re[7]: a = a++; каков результат?
От: Erop Россия  
Дата: 04.05.09 23:55
Оценка: 2 (1) +1
Здравствуйте, igna, Вы писали:

I>Можно подробнее?

А что подробнее. Оба побочных эффекта могут работать РЕАЛЬНО параллельно, и это может быть авостом, выполняемым на железном уровне...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
a = a++; каков результат?
От: ajanov  
Дата: 29.04.09 16:59
Оценка: :))
Все доброго сремени суток!

Сегодня у новичка увидел в коде:


a = a++;



Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".
Re[5]: a = a++; каков результат?
От: Кодт Россия  
Дата: 07.05.09 11:50
Оценка: +1 :)
Здравствуйте, elcste, Вы писали:

E>Чтобы это рассуждение стало нагляднее, представьте себе гипотетическую реализацию, в которой присваивание не атомарно. Например, перед тем, как записать значение в ячейку памяти, ее необходимо очистить влажной тряпочкой.


Кстати, отличный довод — помимо уже многажды упоминавшихся суперскалярных операций.

Например, пишем в EEPROM (флеш-память)
return (x = x0) + (y = y0)
// превращается в
erase(&x); burn(&x, x0);
erase(&y); burn(&y, y0);

return read(x)+read(y); // либо read(x)+y0, либо x0+read(y), либо x0+y0

Если компилятор сочтёт, что удобно сперва сделать erase(&x), erase(&y), а затем burn(&x,x0), burn(&y,y0), то при алиасинге (&x==&y) мы сперва дважды сотрём, а потом дважды прожжём одну ячейку (получив там x0&y0 или x0|y0 в зависимости от технологии).
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Re[5]: И охота тебе троллить начинать? Лучше праздник праздн
От: Masterkent  
Дата: 09.05.09 11:29
Оценка: +1 -1
Erop wrote:

E>IMHO, из описания проблемы следует, что a -- это переменная какого-то интегрального типа.


Почему именно интегрального? Это касается переменных любого встроенного скалярного типа, для которого определён встроенный оператор ++.

E>Что такое стандартные типы С++ -- разберись, пожалуйста, сам...


std::complex<double> — это, по-твоему, стандартный тип или нет?
Re[7]: И охота тебе троллить начинать? Лучше праздник праздн
От: Masterkent  
Дата: 09.05.09 13:00
Оценка: +1 :)
Erop, wrote:

E>Здравствуйте, Masterkent, Вы писали:


M>>Почему именно интегрального? Это касается переменных любого встроенного скалярного типа, для которого определён встроенный оператор ++.


E>потому, что "увеличиться на 1"...


double x = 0;
x++;

Здесь переменная x тоже увеличится на 1, но double — это не integral type (не путать с built-in type). Для intergal types в стандарте имеется следующее определение:

3.9.1/7

Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral types


E>>>Что такое стандартные типы С++ -- разберись, пожалуйста, сам...

M>>std::complex<double> — это, по-твоему, стандартный тип или нет?
E>Нет, конечно...

А вот у авторов стандарта C++, видимо, иное мнение:

18.2.1/4

Non-fundamental standard types, such as complex<T> (26.2.2), shall not have specializations.

Чем ты можешь доказать ошибочность употребления словосочетания "standard types" в этом контексте?
Re[5]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 05.05.09 07:44
Оценка: 8 (1)
Здравствуйте, neFormal, Вы писали:

F>Здравствуйте, Андрей Тарасевич, Вы писали:


F>>>а если ?.

F>>>
F>>>return a++;
F>>>

F>>>тоже UB?.
АТ>>Нет. Откуда?
АТ>>Осмысленность такого кода зависит от того, где определено 'a', но это уже другой вопрос.

F>например, это a — это мембер класса, а return делается в методе

F>
F>a_type Get(){return a++;}
F>

F>т.е. после return-a что то ещё может быть сделано?.

А почему нет? На этом return-е программа же, надеюсь, не заканичает свое существование? Если нет, то "после return-a" еще может быть (и будет) много чего сделано. В частности, на выходе из функции стоит точка следования, значит значение 'a' увеличится еще до выхода из функции.
Best regards,
Андрей Тарасевич
Re[4]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:36
Оценка: -1
Здравствуйте, Alexey F, Вы писали:

_>>Это правило последовательности выполнения операторов, а последовательность такова:

AF>Ничего подобного Это — undefined behavior, ни порядок выполнения, ни последовательность действий при таком раскладе не определены. Компилятор может вписать вместо этого вызов "format D:". И будет прав...

Это не undefined behavior, это unspecified behavior. И никаких "format D:", у компилятора есть выбор из двух возможностей, сначала выполнить присваивание, затем постинкрементирование или наоборот.
Re[3]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 30.04.09 05:41
Оценка: +1
Здравствуйте, igna, Вы писали:

F>>Undefined behavior и есть.


I>Unspecified behavior.


Undefined. Именно undefined.
Best regards,
Андрей Тарасевич
Re[5]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 30.04.09 06:20
Оценка: +1
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Undfined там из стандарта языка. В стандарте сказано — undefined.


I>Где конкретно оно сказано?


Оно сказано в тексте 5/4. Там же располагается пример с комментарием, который якобы утверждает, что behavior unspecified, но это не более чем давняя и хорошо известная опечатка стандарта. В любом случае, примеры в стандарте не являются нормативными и приритет всегда за текстом стандарта. Где сказано, что behavior undefined.
Best regards,
Андрей Тарасевич
Re[5]: a = a++; каков результат?
От: Кодт Россия  
Дата: 07.05.09 11:37
Оценка: +1
Здравствуйте, elcste, Вы писали:

E>P.S. С одной стороны, все это теперь не имеет значения, ибо точек следования больше не будет. С другой стороны, как я понимаю, новый стандарт не выйдет и в этом году...


Как это "точек следования не будет"?
Автоматически рассосутся все проблемы с external aliasing? Или оптимизатор задушат, как автомобили с Евро-4?
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Re[4]: И охота тебе троллить начинать? Лучше праздник праздн
От: Erop Россия  
Дата: 09.05.09 10:26
Оценка: -1
Здравствуйте, BigBoss, Вы писали:

BB>видимо я что-то пропустил, откуда видно, что a -- это стандартный тип? И что это такое вообще "стандартный тип"?

Действительно пропустил...

...однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


IMHO, из описания проблемы следует, что a -- это переменная какого-то интегрального типа.
Что такое стандартные типы С++ -- разберись, пожалуйста, сам...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: И охота тебе троллить начинать? Лучше праздник праздн
От: Erop Россия  
Дата: 09.05.09 12:09
Оценка: -1
Здравствуйте, Masterkent, Вы писали:

M>Почему именно интегрального? Это касается переменных любого встроенного скалярного типа, для которого определён встроенный оператор ++.


потому, что "увеличиться на 1"...

E>>Что такое стандартные типы С++ -- разберись, пожалуйста, сам...

M>std::complex<double> — это, по-твоему, стандартный тип или нет?
Нет, конечно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 29.04.09 17:15
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Сегодня у новичка увидел в коде:



A>
A>a = a++;
A>



A>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


Результат — никакой. Undefined behavior. Никаких правил, по которым, "значение a не должно измениться" нет.
Best regards,
Андрей Тарасевич
Re[4]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 29.04.09 19:04
Оценка:
АТ>В языках С и С++ выражение 'a = a++;' имеет следующую семантику

Имея в виду, что мы игнорируем на минутку факт наличия неопределенного поведения и разбираем это выражение на общих основаниях.
Best regards,
Андрей Тарасевич
Re: a = a++; каков результат?
От: vadimcher  
Дата: 29.04.09 20:53
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Все доброго сремени суток!

A>Сегодня у новичка увидел в коде:

A>
A>a = a++;
A>


A>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


Это еще не самое страшное! Вот код:
#include <iostream>
using namespace std;

int foo (int a) { return a; }

void main(void) {
    int i = 1;
    i = foo ( i++ );
    cout << i << '\n';
}

Ответ должен быть 1? Выводит "1", если компилить в режиме "Debug", и "2" -- в режиме "Release".

А вот зайца кому, зайца-выбегайца?!
Re: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:36
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Сегодня у новичка увидел в коде:


A>a = a++;


Возможно новичок издевался.

A>По правилам C++ значение a не должно измениться


А если сначала будет выполнено присваивание, а лишь потом постинкрементирование?
Re[2]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:38
Оценка:
Здравствуйте, Fwiffo, Вы писали:

F>Undefined behavior и есть.


Unspecified behavior.
Re[5]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 30.04.09 05:40
Оценка:
Здравствуйте, igna, Вы писали:

AF>>Ничего подобного Это — undefined behavior, ни порядок выполнения, ни последовательность действий при таком раскладе не определены. Компилятор может вписать вместо этого вызов "format D:". И будет прав...


I>Это не undefined behavior, это unspecified behavior. И никаких "format D:", у компилятора есть выбор из двух возможностей, сначала выполнить присваивание, затем постинкрементирование или наоборот.


Нет, это именно undefined behavior. Т.е. вплоть до 'format D:'.
Best regards,
Андрей Тарасевич
Re[2]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:41
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Результат — никакой. Undefined behavior.


Откуда там undefined? Unspecified.
Re[3]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 30.04.09 05:43
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>>Результат — никакой. Undefined behavior.


I>Откуда там undefined? Unspecified.


Undfined там из стандарта языка. В стандарте сказано — undefined. Значит undefined. А уж откуда у этого заявления станадарта ноги расут — тема отдельная.
Best regards,
Андрей Тарасевич
Re[4]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:44
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Undefined. Именно undefined.


Вот пример с комментарием из стандарта:


5 Expressions

. . .

4

i = ++i + 1; // the behavior is unspecified

Re[4]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 05:45
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Undfined там из стандарта языка. В стандарте сказано — undefined.


Где конкретно оно сказано?
Re[6]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 06:40
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>В примере — опечатка, которая уже давным-давно обнаружена, рассмотрена, исправлена и закрыта


АТ>http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351


АТ>В тексте же перед примером ясно сказано, что поведение не определено (undefined)


Спасибо. Стандарт неисчерпаем, по крайней мере его ошибки. C++
Re[5]: a = a++; каков результат?
От: Erop Россия  
Дата: 30.04.09 08:17
Оценка:
Здравствуйте, igna, Вы писали:

I>Это не undefined behavior, это unspecified behavior. И никаких "format D:", у компилятора есть выбор из двух возможностей, сначала выполнить присваивание, затем постинкрементирование или наоборот.


Или как-то несинхронизированно обратиться к памяти и обрушить какую-нибудь экзотическую платформу...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: a = a++; каков результат?
От: igna Россия  
Дата: 30.04.09 08:38
Оценка:
Здравствуйте, Erop, Вы писали:

E>Или как-то несинхронизированно обратиться к памяти и обрушить какую-нибудь экзотическую платформу...


Можно подробнее?
Re[2]: a = a++; каков результат?
От: neFormal Россия  
Дата: 04.05.09 19:04
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

A>>
A>>a = a++;
A>>

АТ>Результат — никакой. Undefined behavior. Никаких правил, по которым, "значение a не должно измениться" нет.

а если ?.
return a++;

тоже UD?.
...coding for chaos...
Re[3]: a = a++; каков результат?
От: Vlad_SP  
Дата: 04.05.09 20:00
Оценка:
Здравствуйте, neFormal, Вы писали:

F>а если ?.

F>
F>return a++;
F>

F>тоже UD?.

Нет, конечно. Однако, в большинстве случаев такой код лишен всякого здравого смысла. Если же ожидаются side effects от a++, то проблемы уже не в коде, а в архитектуре....
Re[4]: a = a++; каков результат?
От: neFormal Россия  
Дата: 04.05.09 20:04
Оценка:
Здравствуйте, Vlad_SP, Вы писали:

F>>а если ?.

F>>
F>>return a++;
F>>

F>>тоже UD?.
V_S>Нет, конечно. Однако, в большинстве случаев такой код лишен всякого здравого смысла. Если же ожидаются side effects от a++, то проблемы уже не в коде, а в архитектуре....

конечно, ожидаются side effects.. например, этот a — это какой-нибудь итератор, который зачем-то хранится..
вопрос был задан только в целях самообразования..
...coding for chaos...
Re[4]: a = a++; каков результат?
От: Erop Россия  
Дата: 04.05.09 23:56
Оценка:
Здравствуйте, Vlad_SP, Вы писали:

V_S>Нет, конечно. Однако, в большинстве случаев такой код лишен всякого здравого смысла. Если же ожидаются side effects от a++, то проблемы уже не в коде, а в архитектуре....


Почему? Например, a может быть полем класса, из метода которого return...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: a = a++; каков результат?
От: Андрей Тарасевич Беларусь  
Дата: 05.05.09 06:23
Оценка:
Здравствуйте, neFormal, Вы писали:

A>>>
A>>>a = a++;
A>>>

АТ>>Результат — никакой. Undefined behavior. Никаких правил, по которым, "значение a не должно измениться" нет.

F>а если ?.

F>
F>return a++;
F>

F>тоже UD?.

Нет. Откуда?

Осмысленность такого кода зависит от того, где определено 'a', но это уже другой вопрос.
Best regards,
Андрей Тарасевич
Re[4]: a = a++; каков результат?
От: neFormal Россия  
Дата: 05.05.09 06:36
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

F>>а если ?.

F>>
F>>return a++;
F>>

F>>тоже UB?.
АТ>Нет. Откуда?
АТ>Осмысленность такого кода зависит от того, где определено 'a', но это уже другой вопрос.

например, это a — это мембер класса, а return делается в методе
a_type Get(){return a++;}

т.е. после return-a что то ещё может быть сделано?.
...coding for chaos...
Re[2]: a = a++; каков результат?
От: vadimcher  
Дата: 06.05.09 16:30
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, ajanov, Вы писали:


A>>a = a++;

A>>Так вот вопрос: какой должен быть результат?

V>Это еще не самое страшное! Вот код:

V>#include <iostream>
V>using namespace std;

V>int foo (int a) { return a; }

V>void main(void) {
V>    int i = 1;
V>    i = foo ( i++ );
V>    cout << i << '\n';
V>}

V>Ответ должен быть 1? Выводит "1", если компилить в режиме "Debug", и "2" -- в режиме "Release".

А вот мне самому интересно стало. Ведь, по идее, по стандарту, данная программа ОБЯЗАНА выдать 1, т.к. я специально вставляю вызов функции, чтобы "подвести итоги" перед присваиванием. Оптимизатор же в режиме Release делает функцию насильственно inline, подставляет, вызов функции как таковой пропадает, и получается undefined, которая в случае моего компилятора выдает 2, хотя мог бы выдать и 5. Как такое поведение оптимизатора регламентируется формально, есть ли тому правила/ограничения?

А вот зайца кому, зайца-выбегайца?!
Re[3]: a = a++; каков результат?
От: Erop Россия  
Дата: 06.05.09 16:32
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>А вот мне самому интересно стало. Ведь, по идее, по стандарту, данная программа ОБЯЗАНА выдать 1, т.к. я специально вставляю вызов функции, чтобы "подвести итоги" перед присваиванием. Оптимизатор же в режиме Release делает функцию насильственно inline, подставляет, вызов функции как таковой пропадает, и получается undefined, которая в случае моего компилятора выдает 2, хотя мог бы выдать и 5. Как такое поведение оптимизатора регламентируется формально, есть ли тому правила/ограничения?


Возможно у тебя сотит опция, которая говорит, что не бывает двух ссылок на один объект (external aliases называется, что-ли, короче опция оптимизации a)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: a = a++; каков результат?
От: vadimcher  
Дата: 06.05.09 16:40
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, vadimcher, Вы писали:


V>>А вот мне самому интересно стало. Ведь, по идее, по стандарту, данная программа ОБЯЗАНА выдать 1, т.к. я специально вставляю вызов функции, чтобы "подвести итоги" перед присваиванием. Оптимизатор же в режиме Release делает функцию насильственно inline, подставляет, вызов функции как таковой пропадает, и получается undefined, которая в случае моего компилятора выдает 2, хотя мог бы выдать и 5. Как такое поведение оптимизатора регламентируется формально, есть ли тому правила/ограничения?


E>Возможно у тебя сотит опция, которая говорит, что не бывает двух ссылок на один объект (external aliases называется, что-ли, короче опция оптимизации a)


А что это за опция, и как она влияет в данном случае?

P.S. Сейчас посмотрю, что за зверь.

А вот зайца кому, зайца-выбегайца?!
Re[5]: a = a++; каков результат?
От: Erop Россия  
Дата: 06.05.09 18:30
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>А что это за опция, и как она влияет в данном случае?

V>P.S. Сейчас посмотрю, что за зверь.

Ну оптимизатор считает, что каждая ссылка ссылается на уникальный объект. Ну типа функция
 int f( int& a, int& b ) { return ++a, ++b; }
может компилироваться как
int f( int& a, int& b )
{ 
    int res = ++b;
    ++a;
    return res;
}
не смотря на то, что при вызове
int i = 1;
f( i, i );
будет упс...

Да, у gcc, на каком-то из уровней оптимизации по умолчанию это включено...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: a = a++; каков результат?
От: BigBoss  
Дата: 06.05.09 19:31
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Все доброго сремени суток!


A>Сегодня у новичка увидел в коде:



A>
A>a = a++;
A>



A>Так вот вопрос: какой должен быть результат? По правилам C++ значение a не должно измениться, однако все популярные компиляторы (MSVC, GCC) увеличивают значение на 1, а IAR выдает предуждение "undefined behavior".


operator= (a, a++);
А где в стандарте С++ описан порядок вычисления аргументов???
Re[2]: a = a++; каков результат?
От: Erop Россия  
Дата: 06.05.09 21:32
Оценка:
Здравствуйте, BigBoss, Вы писали:

BB>operator= (a, a++);

BB>А где в стандарте С++ описан порядок вычисления аргументов???

Это тут не при чём, так как (если закрыть глаза на то, что так нельзя) первый аргумент -- это ссылка на a, а второй -- число. Так что тут от порядка ничего зависеть не будет. Ну а вызов функции -- это таки точка следования...
Но a тут -- стандартный тип, так что никакого operator = тут нет, и точки следования нет и всё такое...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: a = a++; каков результат?
От: vadimcher  
Дата: 07.05.09 03:24
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>
V>>#include <iostream>
V>>using namespace std;

V>>int foo (int a) { return a; }

V>>void main(void) {
V>>    int i = 1;
V>>    i = foo ( i++ );
V>>    cout << i << '\n';
V>>}
V>

V>>Ответ должен быть 1? Выводит "1", если компилить в режиме "Debug", и "2" -- в режиме "Release".

V>А вот мне самому интересно стало. Ведь, по идее, по стандарту, данная программа ОБЯЗАНА выдать 1, т.к. я специально вставляю вызов функции, чтобы "подвести итоги" перед присваиванием. Оптимизатор же в режиме Release делает функцию насильственно inline, подставляет, вызов функции как таковой пропадает, и получается undefined, которая в случае моего компилятора выдает 2, хотя мог бы выдать и 5. Как такое поведение оптимизатора регламентируется формально, есть ли тому правила/ограничения?


Хорошо, поясню свой вопрос. Есть код:
i=1; i = i++;

Некто ожидает, что порядок выполнения следующий:
1) i=1;
2) i++; возвращает 1 и увеличивает i на 1, т.е. i=2;
3) i=1;
Стандарт на это говорит, что порядок вычислений следующий:
1) i=1: возвращает 1, побочное действие записать 1 в i;
2) записывает 1 в i;
3) i++ возвращает 1, побочное действие: увеличить i на 1;
4) i=i++ возвращает 1, побочное действие: записать 1 в i;
5) выполнение всех побочных действий в любом порядке.

Хорошо, стандарт есть стандарт. В соответствии со стандартом, чтобы первое побочное выполнилось до второго (строго в этом порядке) нам надо явно указать компилятору, чтобы тот перед присвоением не забыл увеличить i, а не наоборот. Для этого перед присвоением вызываем функцию, которая возвращает результат, равный значению на входе:
i = 1; i = foo ( i++ );
В соответствии со стандартом, теперь:
1) i=1: возвращает 1, побочное действие записать 1 в i;
2) записывает 1 в i;
3) i++ возвращает 1, побочное действие: увеличить i на 1;
4) 1 передается как параметр функции, перед этим выполняются все побочные эффекты: i увеличивается на 1, т.е. i=2;
5) foo() возвращает 1;
6) i=foo() возвращает 1, побочное действие: записать 1 в i;
7) выполнение всех побочных действий: i=1.

Теперь, оптимизатор. Оптимизатор, по своей сути, должен оптимизировать, чтобы код выполнялся быстрее или требовал меньше памяти, но логика программы сохранялась. Т.е. в данном случае от оптимизатора ожидается следующее:
1) i=1: возвращает 1, побочное действие записать 1 в i;
2) записывает 1 в i;
3) i++ возвращает 1, побочное действие: увеличить i на 1;
4) выполняются все побочные эффекты: i увеличивается на 1, т.е. i=2;
5) i=1 возвращает 1, побочное действие: записать 1 в i;
6) выполнение всех побочных действий: i=1.

Т.е. функция явно не вызывается, а результат ее работы подставляется. Что же делает оптимизатор? Он не просто оптимизирует выполнение кода, а он приводит выражение обратно к i=i++, а далее компилирует так, будто это и есть то, что написано в коде, при этом нарушая логику работы, когда ему явно был указан порядок выполнения увеличения i и присвоения значения в i (в соответствии со стандартом). Короче, оптимизатор оптимизирует код так, будто там есть undefined, когда его там и в помине нет.

А вот зайца кому, зайца-выбегайца?!
Re[4]: a = a++; каков результат?
От: Кодт Россия  
Дата: 07.05.09 09:54
Оценка:
Здравствуйте, vadimcher, Вы писали:

VV>Стандарт на это говорит, что порядок вычислений следующий:

Стандарт на это говорит, что порядок не определён, и в следствие этого получаем либо неспецифицированное, либо неопределённое (в данном случае) поведение.
Дальнейшие твои рассуждения исходят из неправильной посылки, так что их можно пропустить.

Рассмотрим выражение a = b++.
До вычисления (a,b) принимают значения (a0,b0).
После вычисления (a,b) = (b0,b0+1).

Если &a == &b, то вопрос: чему же будет равна эта переменная? Да чему попало!
Это уже, как минимум, неспецифицированное поведение.

Теперь почему у компилятора развязаны руки: фокус в том, что получить пару чисел (b0,b0+1) можно разными способами.
a = b, b = b+1
b = b+1, a = b-1
c = b, b = b+1, a = c
и т.п.
И это в том случае, если у нас строго скалярная архитектура.
А если векторная или суперскалярная, то компилятор может сформировать операцию групповой записи
(&a, &b) <- (b, b+1)
Раз нет точек следования, то и барьеров памяти (дополнительных тормозов) тоже нет. Но при групповой записи в одну ячейку может случиться страшное.
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Re[4]: a = a++; каков результат?
От: elcste  
Дата: 07.05.09 10:39
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>>А вот мне самому интересно стало. Ведь, по идее, по стандарту, данная программа ОБЯЗАНА выдать 1, т.к. я специально вставляю вызов функции, чтобы "подвести итоги" перед присваиванием. Оптимизатор же в режиме Release делает функцию насильственно inline, подставляет, вызов функции как таковой пропадает, и получается undefined, которая в случае моего компилятора выдает 2, хотя мог бы выдать и 5. Как такое поведение оптимизатора регламентируется формально, есть ли тому правила/ограничения?


Когда-то давно это здесь уже обсуждали. Консенсус, как мне помнится, так и не был найден. На мой взгляд, поведение MSVC вполне допускается действующим стандартом.

V>Хорошо, поясню свой вопрос. Есть код:
i=1; i = i++;

V>Стандарт на это говорит, что порядок вычислений следующий:

Собственно, стандарт говорит, что "the behavior is undefined". Дальнейшие рассуждения о порядке вычислений не имеют смысла.

i = 1; i = foo ( i++ );

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

Чтобы это рассуждение стало нагляднее, представьте себе гипотетическую реализацию, в которой присваивание не атомарно. Например, перед тем, как записать значение в ячейку памяти, ее необходимо очистить влажной тряпочкой.


P.S. С одной стороны, все это теперь не имеет значения, ибо точек следования больше не будет. С другой стороны, как я понимаю, новый стандарт не выйдет и в этом году...
Re[6]: a = a++; каков результат?
От: jazzer Россия Skype: enerjazzer
Дата: 07.05.09 12:17
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, elcste, Вы писали:


E>>P.S. С одной стороны, все это теперь не имеет значения, ибо точек следования больше не будет. С другой стороны, как я понимаю, новый стандарт не выйдет и в этом году...


К>Как это "точек следования не будет"?

К>Автоматически рассосутся все проблемы с external aliasing? Или оптимизатор задушат, как автомобили с Евро-4?

Будет sequencing. Само понятие точек следования изчезнет.
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: a = a++; каков результат?
От: TimurSPB Интернет  
Дата: 10.05.09 01:41
Оценка:
Морду надо бить за такой код!
Make flame.politics Great Again!
Re[6]: a = a++; каков результат?
От: vadimcher  
Дата: 10.05.09 19:36
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>Здравствуйте, elcste, Вы писали:


M>
i = 1; i = foo ( i++ );

E>>Относительно побочного эффекта постинкремента мы знаем, что он должен выполниться до точки следования перед входом в функцию. Но для присваивания ограничение только одно: до конца полного выражения. И хотя здравый смысл подсказывает, что это может произойти только после выхода из функции, буква стандарта никак это не подтверждает.

M>Буква стандарта много чего не подтверждает. Полагаться на здравый смысл всё равно приходится.


M>
std::string f()
M>{
M>    {
M>        std::string s = "text";
M>        return s;
M>    }
M>}

M>Попробуй-ка найти в стандарте подтверждение тому, что выход управления из scope с объявлением s и сопутствующее ему уничтожение объекта s не может произойти до того, как будет произведена попытка скопировать значение s во временный объект, создаваемый в контексте возврата.

E>>Чтобы это рассуждение стало нагляднее, представьте себе гипотетическую реализацию, в которой присваивание не атомарно. Например, перед тем, как записать значение в ячейку памяти, ее необходимо очистить влажной тряпочкой.


M>Абстрактную машину и реализацию следует рассматривать отдельно. Понятие точек следования служит только в целях формализации работы абстрактной машины. Эмулируя одно из возможных наблюдаемых поведений абстрактной машины, реализация не обязана копировать или эмулировать структуру самой абстрактной машины и тем более подчиняться правилам, сформулированным в отношении точек следования (1.9). Для абстрактной машины присваивание определяется следующим образом (5.17/2):

M>

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

M>Очевидно, такая замена значения не может состояться до того, как будет получен объект, являющийся результатом вычисления правого операнда (нет возвращаемого функцией объекта — нет и значения выражения). Каких-то дополнительных действий, кроме осуществления данной замены, стандарт в отношении абстрактной машины, насколько я знаю, не предусматривает. Таким образом, мы получаем, что на абстрактной машине значение правого операнда формируется после точки следования, которая отделяет дальнейшее присваивание от предшествующего инкремента.

M>При ином раскладе вычисление подобного выражения может прекратиться до присваивания:


M>
int g(int x);

M>void f(int &i)
M>{
M>    i = g(i++); // may throw
M>}

M>Если функция g сгенерирует исключение, то результирующий объект для выражения g(i++) попросту не будет создан, а потому не будет и значения, которым можно было бы заменить значение левого операнда. Разрешения каким-либо образом портить i в таком случае я в стандарте не встречал.

M>Каким образом реализация будет эмулировать одно из допустимых observable behavior абстрактной машины — это уже проблемы реализации. В случае


M>
#include <iostream>

M>int foo (int x) { return x; }

M>int main()
M>{
M>    int i = 1;
M>    i = foo(i++);
M>    std::cout << i << std::endl;
M>}

M>вывод должен быть строго "1".

Да, мне тоже так казалось...

А вот зайца кому, зайца-выбегайца?!
Re[5]: a = a++; каков результат?
От: vadimcher  
Дата: 10.05.09 19:42
Оценка:
Здравствуйте, elcste, Вы писали:

E>
i = 1; i = foo ( i++ );

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

В любом случае присваивание не может быть осуществлено до входа в функцию, т.к. по стандарту сначала вычисляется выражение справа, а осуществление инкремента должно быть до входа. И проблема здесь в том, что при оптимизации тело функции подставляется и второе требование отпадает...

E>P.S. С одной стороны, все это теперь не имеет значения, ибо точек следования больше не будет. С другой стороны, как я понимаю, новый стандарт не выйдет и в этом году...

А вот зайца кому, зайца-выбегайца?!
Re[5]: a = a++; каков результат?
От: vadimcher  
Дата: 10.05.09 20:07
Оценка:
Здравствуйте, elcste, Вы писали:

E>
i = 1; i = foo ( i++ );

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

E>Чтобы это рассуждение стало нагляднее, представьте себе гипотетическую реализацию, в которой присваивание не атомарно. Например, перед тем, как записать значение в ячейку памяти, ее необходимо очистить влажной тряпочкой.


Это все конечно здорово, но не очень понятно, как это связано в данном случае с проблемой. Ясно, что такое "протирание" будет после использования данной ячейки, а иначе компилятор и такое i=i может во что угодно скомпилировать.

А вот зайца кому, зайца-выбегайца?!
Re[6]: a = a++; каков результат?
От: Masterkent  
Дата: 10.05.09 21:02
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, elcste, Вы писали:


E>>
i = 1; i = foo ( i++ );

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

V>В любом случае присваивание не может быть осуществлено до входа в функцию


Целиком не может — потому что до входа в функцию значение, которое нужно присвоить, ещё не существует. Произвести часть side-эффектов, относящихся к присваиванию, до точки следования и часть после абстрактная машина также не может — ввиду 1.9/7 ("At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place"). Таким образом, присваивание целиком попадает за точку следования на входе функции.

V>И проблема здесь в том, что при оптимизации тело функции подставляется и второе требование отпадает...


Эта оптимизация относится к реализации, а не абстрактной машине. Если в результате такой оптимизации функция вывода выдаёт нам результат, который не может получиться на абстрактной машине, то это не что иное, как нарушение стандарта.
Re[7]: a = a++; каков результат?
От: vadimcher  
Дата: 10.05.09 23:13
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>Эта оптимизация относится к реализации, а не абстрактной машине. Если в результате такой оптимизации функция вывода выдаёт нам результат, который не может получиться на абстрактной машине, то это не что иное, как нарушение стандарта.


Вот, так именно в этом и мой вопрос.

А вот зайца кому, зайца-выбегайца?!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.