2017-02-03 10 views
21

Я знаю, что i=i++; является неопределенным поведением, потому что i изменяется дважды до точки последовательности ;.Является ли следующее неопределенным поведением? i = func (i)

Но я не знаю, если компилятор гарантирует случай, как показано ниже, не является неопределенным поведением:

int func(int &i) 
{ 
    i++; 
    return i; 
} 

int i = 1; 
i = func(i); 
+0

, что говорит компилятор? – tristan

+24

@tristan, как правило, компилятор ничего не говорит о UB. – user2079303

+0

gcc имеет опцию «-Последняя точка» – tristan

ответ

44

Во-первых, современный C++ перешел от старого (неадекватной) концепции «точек последовательности» в новая концепция «секвенирования» (т.е. «секвенирована раньше», «упорядочена после»). Пока i = i++ по-прежнему не определено, i = ++i на самом деле отлично определено сейчас. Правила секвенирования во многих возвращающих lvalue операциях были переработаны.

Во-вторых, ваша версия безопасна по старой спецификации, а также по новой. Модификация i внутри функции безопасно «изолирована» от назначения до i снаружи. В классических точках последовательности функций в начале и в конце функции безопасно отделяются изменения (и чтения) от i друг от друга. Новые правила последовательности сохраняют тот же уровень защиты.

Пример, который иллюстрирует защиту, обеспечиваемую вызов функции может выглядеть следующим образом

int inc(int &i) { return i++; } 
... 
int i = 1; 

int r1 = i++ * i++ * i++;   
// Undefined behavior because of multiple unsequenced side effects 
// applied to the same variable 

int r2 = inc(i) * inc(i) + inc(i); 
// No UB, but order of evaluation is unspecified. Since the result 
// depends on the order of evaluation, it is unspecified 

int r3 = inc(i) + inc(i) + inc(i); 
// Perfectly defined result. Order of evaluation is still unspecified, 
// but the result does not depend on it 
+0

«Модификация i внутри функции безопасно« изолирована »от назначения на i снаружи». Что делать, если компилятор встраивает функцию? Или потенциал UB означает, что компилятор не будет встраивать этот конкретный случай? – JAB

+4

@ JAB: Inlining никоим образом не изменяет семантику последовательности (или любую другую семантику) вызова функции. Компилятор может свободно встраивать все, что захочет, в любой момент, но полученный код должен полностью сохранять исходную абстрактную семантику. То есть поведение встроенного вызова должно быть таким же, как поведение неинтерминированного вызова. В этом случае нет ничего, чтобы предотвратить компилятор от встраивания. Но компилятор должен помнить, что встроенная версия полностью сохраняет поведение не-встроенного. – AnT

+0

Хорошо, это хорошо, учитывая, что я использовал такое поведение в прошлом. – JAB