Re: Sequence Points и присваивание
От: Arks Россия  
Дата: 27.02.13 10:51
Оценка: 1 (1)
Здравствуйте, Фаллопиева труба, Вы писали:

ФТ>Здравствуйте.


ФТ>Получается что у следующего кода undefined behaviour.


ФТ>Что думаете по этому поводу? А ведь люди используют это.

ФТ>
ФТ>class A
ФТ>{
ФТ>};

ФТ>A *factory()
ФТ>{
ФТ>    return new A;
ФТ>}

ФТ>void f()
ФТ>{
ФТ>    A *instance = 0;

ФТ>    if ((instance = factory) != 0) // undefined behaviour: no sequence points here
ФТ>    {
ФТ>        // do work with instance
ФТ>    }
ФТ>}
ФТ>


Здравствуйте.

Очень заинтересовало обсуждение и заставило разобраться с sequence point'ами.
Да, здесь одна точка следования, но UB (undefined behaviour / неопредлённое поведение) здесь нет. По крайней мере в c++03.
c++03 $5.17/1:

The result of the assignment operation is the value stored in the left operand after the assignment has taken place.

Результат оператора присваивания — это значение, которое после выполнения присваивания записано в левый операнд.
Точки следования определяют, когда точно произойдут все побочные эффекты в выражении, а не когда его значение будет вычислено ($1.9/7):

Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression might produce side effects. At certain specified points in the execution sequence calledsequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

Побочный эффект оператора присваивания — не вычисление и возврат результата, а его запись в объект (modifying an object).
Таким образом до точки следования instance может не получить своё новое значение, но это значение оператор присваивания уже вычислил и вернул в качестве результата, который далее используется как аргумент оператора не равенства.


(instance = factory()) != 0;

// По шагам с записью промежуточных результатов во временные переменные:
1 tmp1 <- factory(); // вернули значение из функции
2 tmp2 <- instance = tmp1; // вернули результат оператора присвоения. Получили значение первого операнда.
3 tmp3 <- 0 - второй операнд для "не равно". Замечу, что он мог вычислиться и раньше первого
4 tmp4 <- tmp2 != tmp3; // получили результат операции "не равно"
5 дошли до ; (или другой точки следования), теперь мы точно знаем, что выполнилось: instance <- tmp1
[ccode]

Мы бы имели UB здесь, если бы попытались повторное использовать instance, скажем вот так:
[ccode]
if ((instance = factory()) != instance->parent)

Здесь instance во втором операнде оператора "не равно", даже если этот операнд вычислится после вычисления первого операнда, может иметь значение 0, так как побочный эффект присваивания мог не произойти.


ФТ>В новом стандарте это вообще undefined behaviour. В старом тоже. Сам пользовался такой конструкцией. Собственно вопрос: стандарт разве гарантирует ФТ>что присвоение произойдет раньше сравнения?

Стандрарт c++11 вообще явно гарантирует, что операнды будут вычислены раньше результата ($1.9/15):

The value computations of the operands of an
operator are sequenced before the value computation of the result of the operator

Про запись значения в объект (побочный эффект) опять-таки нет ни слова, но тут я пока ничего не скажу, не разобрался ещё в деталях для c++11.

[b]НЕ ИСПОЛЬЗУЙТЕ ТЭГ [code] ДЛЯ ЦИТИРОВАНИЯ.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.