以下是未定义的行为吗?i = func(i)

Yve*_*ves 21 c++ undefined-behavior

我知道这i=i++;是一个未定义的行为,因为i在序列点之前更改了两次;.

但我不知道编译器是否保证这种情况,如下所示不是一个未定义的行为:

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

int i = 1;
i = func(i);
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 44

首先,现代C++已经从旧的(不充分的)"序列点"概念转变为"排序"的新概念(即"之前排序","之后排序").虽然i = i++仍未定义,但i = ++i实际上现在已经完美定义了.许多左值返回运算符中的排序规则被重新编写.

其次,您的版本在旧规范下以及在新规范下都是安全的.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
Run Code Online (Sandbox Code Playgroud)

  • @JAB:内联不会以任何方式改变函数调用的排序语义(或任何其他语义).编译器可以随时内联它想要的任何内容,但结果代码必须完全保留原始的抽象语义.即内联调用的行为必须与非内联调用的行为相同.在这种情况下,没有什么可以阻止编译器内联.但编译器必须记住,内联版本应完全保留非内联版本的行为. (4认同)