重复使用前缀 ++ 运算符时的未定义行为
Undefined behaviour in repeated use of prefix ++ operator
我读到了这个关于未定义行为的答案,我看到了以下陈述:
++++++i; // UB, parsed as (++(++(++i)))
我不认为这是未定义的行为。我有一个疑问,它真的是C++中的UB?如果是,那么如何?
另外,我使用g++ prog.cpp -Wall -Wextra -std=gnu++1z -pedantic
命令制作了程序并进行编译,它工作正常,没有任何警告。它给出了预期的输出。
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout<<++++++i<<endl;
}
在 C++03 中,它是未定义的行为。在C++11中不是。各种预递增之间没有序列点。如果i
是用户定义的类型,它将是定义良好的行为,因为这样就会有一个函数调用(序列点)。
在C++11 中,序列点的概念被之前/之后的序列所取代。缺陷 637 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637) 提供了一个以前未定义的构造变得明确定义 (i = ++i + 1
) 的示例。
为了理解为什么它不是未定义的行为,让我们看看我们需要的部分。++i
等效于i = i + 1
(除了i
只计算一次)。此外,如果我们用inc
代替i = i + 1
,++(i = i + 1)
变得inc = inc + 1
。
[expr.ass] 指出:
在所有情况下,赋值都是在左右操作数的值计算之后以及赋值表达式的值计算之前排序的。
因此,i = i + 1
中的赋值是在inc
的值计算之前排序的;然而,inc = inc + 1
中的赋值是在inc
的值计算之后排序的。没有未定义的行为,因为分配是按顺序排列的。
有时行为是未定义的,即使很难想象它是如何被错误处理的。但是在C++11之前,这是未定义的,因为同一对象被多次修改而没有指向干预序列。
可以想象一个编译器,它通过合并所有修改来"优化"代码i
.因此,每个增量都会递增原始值。但这不是重点。如果标准这么说,UB 就是 UB。我们是否能想象它是如何失败的并不重要。
- 体系结构x86_64的未定义符号:std:terminate(),typeinfo,运算符delete[],运算符new
- 未定义的引用和运算符 << vs me
- C++:对函子重载调用运算符的未定义引用
- 对模板运算符的未定义引用,其定义位于同一头文件中
- 在 tensorflow-GPU 中使用用户运算符时未定义的符号>=1.15
- 为什么T是未定义的?我正在尝试实现一个用于双链表的节点类,它不喜欢我使用友元运算符后的T
- 调用提取重加载器会产生对"运算符"的未定义引用错误>>
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 编译Qt项目给出了对运算符delete(void*,unsigned int)的未定义引用
- 在 C 和 C++ 中,使用逗号运算符的表达式是否未定义"a = b, ++a;"?
- 未定义对运算符的引用!= 使用 std::unordered_set 时
- C2676 - 二进制'++'未定义此运算符
- 未定义 Lambda 复制分配运算符
- 为什么要重载以前未定义的运算符
- std::可选运算符*() 和运算符>() - 未定义的行为
- 对运算符>>的未定义引用会导致LINK2019
- 重复使用前缀 ++ 运算符时的未定义行为
- 当c 中的矢量容器过载[]运算符时,我对未定义的索引返回什么
- std::映射运算符[]--未定义的行为
- C2676 二进制"++":设置迭代器<TElement>未定义此运算符