为什么 mySet.erase(it++) 不是未定义的行为,还是?
Why isn't mySet.erase(it++) undefined behavior, or is it?
根据这个相当高投票的答案,迭代一个集合擦除一些元素的规范方法如下:
for (it = mySet.begin(); it != mySet.end(); ) {
if (conditionToDelete(*it)) {
mySet.erase(it++);
}
else {
++it;
}
}
当然,这是 C++03 的集合擦除不返回迭代器的结果。否则可以写it = mySet.erase(it);
很明显,一个人可以写
itToDelete = it++;
mySet.erase(itToDelete);
这个问题不是关于如何在迭代时删除元素。问题是为什么以下行显然不会导致未定义的行为。
mySet.erase(it++);
起初,我确信这一定是 UB,因为我对后期增量的想法是错误的。这是一种常见(但错误)的方式,将前增量视为在评估的其余部分之前发生,而后增量发生在评估之后。当然,这是错误的。后增量和预递增都有递增变量的副作用。区别在于这些表达式的值。
也就是说,据我所知,C++标准(至少是 C++03 标准)并没有确切说明后增量的副作用何时发生。所以,除非我们保证如果一个作为后增量表达式的函数参数在进入函数体之前会有副作用,否则这不应该是 UB?究竟是什么(标准方面),如果有的话,禁止在迭代器在函数体内失效后发生 it++ 的副作用?
非常欢迎引用标准。
为了参数的缘故,我们还假设set的迭代器是内置类型,这实际上是运算符++,而不是重载的运算符函数
这不是 C++03 中的未定义行为,因为在计算所有函数参数后都有一个序列点。
最接近 C++03 且公开可用的标准草案是 N1804,我找不到之前的标准草案的公开版本,但维基百科关于使用 C++98 和 c++03 作为参考的序列点的文章,短语与 N1804 的以下段落一致。
在第1.9
节"计划执行"中,第16段说(强调我的前进):
调用函数时(无论函数是否内联),在计算所有函数参数(如果有)之后,在执行函数体中的任何表达式或语句之前,都会有一个序列点。[...]
后来在第 5.2.2
节中函数调用第 8 段说:
参数的计算顺序未指定。参数表达式计算的所有副作用在输入函数之前生效。未指定后缀表达式和参数表达式列表的计算顺序。
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 未定义的引用在哪里
- 编译时的 CImg 库返回对"__imp_SetDIBitsToDevice"的未定义引用
- 对Py_Initialize()的未定义引用
- c++11评估顺序(未定义的行为)
- 使用mysql c++连接器的未定义引用
- 从python调用openMP共享库时,未定义opnMP函数
- 在 Mac 上使用 CMAKE 将 FFTW 和 FFTWPP 链接到项目中时未定义的符号
- Cmake 链接问题:未定义对 Button::mousePressEvent(QGraphicsSceneMouseE
- 未定义的引用 .. 使用 OpenCV 编译 C++ 代码时,从命令行
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- std::rethrow_exception(nullptr) 未定义的行为还是bad_exception?
- 双循环变量的相等条件:未指定还是未定义
- 规避类的构造函数是合法的还是会导致未定义的行为?
- 为什么 mySet.erase(it++) 不是未定义的行为,还是?