什么是"序列点"?
未定义的行为和序列点之间的关系是什么?
我经常使用有趣和复杂的表达方式a[++i] = i;,让自己感觉更好.我为什么要停止使用它们?
如果您已阅读此内容,请务必访问后续问题重新加载未定义的行为和序列点.
(注意:这是Stack Overflow的C++常见问题解答的一个条目.如果你想批评在这种形式下提供常见问题解答的想法,那么发布所有这些的元数据的发布将是这样做的地方.这个问题在C++聊天室中受到监控,其中FAQ的想法一开始就出现了,所以你的答案很可能被那些提出想法的人阅读.)
好吧,我知道标准规定C++实现可以选择评估函数的哪个顺序参数,但是在实际影响程序的情况下是否有任何实现"利用"它的实现?
经典示例:
int i = 0;
foo(i++, i++);
Run Code Online (Sandbox Code Playgroud)
注意:我不是在找人告诉我评估的顺序不能依赖,我很清楚这一点.我只对任何编译器是否真的按照从左到右的顺序进行评估感兴趣,因为我的猜测是,如果他们做了很多写得不好的代码就会破坏(这是正确的,但他们仍然可能会抱怨).
在C++中,以下是否有未定义的行为:
int i = 0;
(i+=10)+=10;
Run Code Online (Sandbox Code Playgroud)
在我对C和C++中+ =的结果的答案的评论中有一些争论?这里的微妙之处在于默认响应似乎是"是",而正确的答案似乎是"它取决于C++标准的版本".
如果它确实取决于标准的版本,请解释UB的位置和不在的位置.
在C++中,预增量运算符给出左值,因为返回了递增的对象本身,而不是副本.但在C中,它给出了右值.为什么?
此代码取自此处的讨论.
someInstance.Fun(++k).Gun(10).Sun(k).Tun();
Run Code Online (Sandbox Code Playgroud)
这段代码是否定义明确?是否++k在kSun()之前评估过Fun ()?
如果k是用户定义的类型,而不是内置类型怎么办?以上函数调用顺序的方式与此不同:
eat(++k);drink(10);sleep(k);
Run Code Online (Sandbox Code Playgroud)
据我所知,在这两种情况下,每个函数调用后都存在一个序列点.如果是这样,为什么第一个案例也不能像第二个案例那样明确定义?
C++ ISO标准的1.9.17部分对序列点和功能评估进行了说明:
在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有) 之后,都会有 一个序列点.在复制返回值之后和执行函数外部的任何表达式之前,还有一个 序列点.
考虑到成本,这些情况是否相同?
// case 1
int a = 5;
// case 2
int a (5);
// case 3
int a;
a = 5
Run Code Online (Sandbox Code Playgroud) 以下表达式通常用于演示未定义的未指定行为:
f() + g()
Run Code Online (Sandbox Code Playgroud)
如果f()和g()都有一些共享对象的副作用,则行为是不确定的不确定,因为执行的顺序是未知的.f()可以在之前评估,g()反之亦然.
现在我想知道当你在一个对象上链接成员函数时会发生什么.比方说,我有一个类,叫做实例的实例obj,它有两个成员函数,foo()而bar()这两个修改的对象.这些函数的执行顺序不是可交换的.在一个接一个之前调用一个的效果与用另一个方式调用它们的效果不同.这两个方法都返回一个引用,*this以便它们可以像这样链接:
obj.foo().bar()
Run Code Online (Sandbox Code Playgroud)
但这是不明确的行为吗?我在标准中找不到任何东西(不可否认只是扫描),区分了这个表达式和我在帖子顶部给出的表达.两个函数调用都是full-expression的子表达式,因此它们的执行顺序是未指定的.但肯定foo() 必须先评估,以便bar()知道要修改哪个对象.
也许我错过了一些明显的东西,但我无法看到序列点的创建位置.
这样定义,我们既不做++x++也不做++x--.但另一方面,无论是(++x)++和(++x)--是有用的表达式:(++x)++增量x由两个并返回"中间"的价值,而(++x)--实质上等同于x+1而是完全避免了打电话operator+,这是非常有用的时候.
那么为什么没有定义的优先级++x++自动扩展到(++x)++而不是++(x++)?对于后者有一些隐藏的含义,我不明白,或者只是将优先级保持为一个简单的列表,所有前缀运算符组成一个单一的级别?
编辑好的,我没有明确说出来,但是:当然我的意思x是用户定义的类型.对于内置类型,(x+=2)-1当然比更好的(++x)++,并且x+1是一个很多好过(++x)--.我想到的情况是一个相当复杂的半关联容器的迭代器,其中运算符+=和+(为随机访问而设计)必须重建缓存才能有效地处理一般请求,因此是一个命令比...慢++.但是我当然可以将它们修改为总是首先检查参数是否是一个非常小的整数,并且在这种情况下只是operator++反复调用而不是执行随机访问过程.这应该可以正常工作,虽然我可以想象我可能在某种程度上有一种情况,我想operator+=总是采用随机访问方式,无论我呈现的数字有多少.
具有简单的和精心memorizeable优先列表,其中的优点所有之前来后缀运算符任何前缀运营商足以容忍的总是不必使用括号来构成前和后缀运算符的小缺点
++/--,因为该组合物是非常少用.
更简单的"C就是这样做的",虽然看起来可能是真正的原因,但对我来说远不那么令人满意,因为C中++x++根本不允许这样做,所以可以重新定义这个非常复杂的构图而不会损坏任何构图.现有代码.
无论如何,我会继续使用(++x)--,因为括号真的没有那么多伤害.
c++ increment operator-precedence prefix-operator postfix-operator
可能重复:
未定义的行为和序列点
x这段代码后的价值是多少?
int x = 5;
x = ++x + x++;
Run Code Online (Sandbox Code Playgroud)
在Java中,结果是12,但在C++中,结果是13.
我搜索了Java和C++的运算符优先级,它们看起来一样.那么为什么结果不同呢?是因为编译器吗?
我在cppreference上遇到了评估顺序页面,我无法理解为什么这些行被视为未定义行为。
i = ++i + 2; // undefined behavior until C++11
f(i = -2, i = -2); // undefined behavior until C++17
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,不是先++i计算赋值,然后是求和,然后是最终赋值i?
第二种情况呢?在我看来,该函数将同时获得参数as -2和的值i将始终-2在执行之后。