作者:mobiledu2502861137 | 来源:互联网 | 2023-01-22 03:25
我正在读这个问题:
未定义的行为和序列点
并且,特别是C++ 11的答案,我理解评估的"排序"的想法.但是 - 写作时是否有足够的顺序:
f(x++), g(x++);
?
也就是说,我保证f()
获得原始值x
并g()
获得一次递增x
?
挑剔的注意事项:
假设operator++()
已定义的行为(即使我们已经重写它),这样做f()
和g()
,没有异常将被抛出,等-这个问题是不是有关.
假设operator,()
没有超载.
StoryTeller ..
49
不,行为已定义.引用C++ 11(n3337)[expr.comma/1]:
用逗号分隔的一对表达式从左到右进行评估; 左表达式是一个废弃值表达式(Clause [expr]).
在与右表达式相关联的每个值计算和副作用之前,对与左表达式相关联的每个值计算和副作用进行排序.
我把"每一个"都称为"每一个" 1.x++
在呼叫序列f
完成并f
返回之前,不能进行第二次评估.2
1析构函数调用与子表达式无关,仅与完整表达式相关联.因此,您将看到在完整表达式结束时以相反顺序执行的临时对象创建.
2本段仅适用于作为运营商使用的逗号.当逗号具有特殊含义时(例如在指定函数调用参数序列时),这不适用.
1> StoryTeller ..:
不,行为已定义.引用C++ 11(n3337)[expr.comma/1]:
用逗号分隔的一对表达式从左到右进行评估; 左表达式是一个废弃值表达式(Clause [expr]).
在与右表达式相关联的每个值计算和副作用之前,对与左表达式相关联的每个值计算和副作用进行排序.
我把"每一个"都称为"每一个" 1.x++
在呼叫序列f
完成并f
返回之前,不能进行第二次评估.2
1析构函数调用与子表达式无关,仅与完整表达式相关联.因此,您将看到在完整表达式结束时以相反顺序执行的临时对象创建.
2本段仅适用于作为运营商使用的逗号.当逗号具有特殊含义时(例如在指定函数调用参数序列时),这不适用.
@StoryTeller:对不起,好的,谢谢,这绝对违反直觉:*"销毁临时对象的价值计算和副作用只与全表达有关,而与任何特定的子表达无关."*绝对不是我所期望的从逻辑上讲,析构函数调用表达式*与它相关联.我建议在你的回答中添加析构函数调用,因为它会向那些没有阅读标准的人提出建议......
2> Some program..:
不,它不是未定义的行为.
根据此评估顺序和排序参考,逗号的左侧在右侧之前完全评估(参见规则 9):
9)内置逗号运算符的第一个(左)参数的每个值计算和副作用在每个值计算和第二个(右)参数的副作用之前排序.
这意味着像的表达f(x++), g(x++)
是不未定义.
请注意,这仅对内置逗号运算符有效.
并且,为了强调,这不是C++ 11独有的.自远古以来就是如此.
3> Deduplicator..:
这取决于.
首先,让我们假设它x++
本身不会调用未定义的行为.考虑有符号溢出,递增过去的结束指针,或者postfix-increment-operator可能是用户定义的).
此外,让我们假设调用f()
和g()
使用他们的参数并销毁临时对象不会调用未定义的行为.
这是相当多的假设,但如果它们被打破,答案是微不足道的.
现在,如果逗号是内置的逗号操作符,逗号的支撑,初始化列表,或在MEM-初始化列表中的逗号,左侧和右侧分别之前或之后彼此测序(和你知道哪个),所以不要干涉,使行为定义明确.
struct X {
int f, g;
explicit X(int x) : f(x++), g(x++) {}
};
// Demonstrate that the order depends on member-order, not initializer-order:
struct Y {
int g, f;
explicit Y(int x) : f(x++), g(x++) {}
};
int y[] = { f(x++), g(x++) };
否则,如果x++
为postfix-increment调用用户定义的operator-overload,则会对两个实例进行不确定的排序,x++
从而对未指定的行为进行排序.
std::list list{1,2,3,4,5,6,7};
auto x = begin(list);
using T = decltype(x);
void h(T, T);
h(f(x++), g(x++));
struct X {
X(T, T) {}
}
X(f(x++), g(x++));
在最后一种情况下,你得到了完整的未定义行为,因为两个后缀增量x
是未经测序的.
int x = 0;
void h(int, int);
h(f(x++), g(x++));
struct X {
X(int, int) {}
}
X(f(x++), g(x++));