用作 std::multimap 擦除范围的第一个和最后一个的递增迭代器
Incrementing iterator that is used as first and last of std::multimap erase range
在运行一个示例来展示如何从 std::map/multimap 中删除范围时,我注意到以下代码中存在奇怪的行为:
#include <map>
#include <iostream>
#include <string>
int main()
{
std::multimap<int, std::string> myMap;
myMap.insert(std::make_pair(3, "three1"));
myMap.insert(std::make_pair(3, "three2"));
myMap.insert(std::make_pair(3, "three3"));
myMap.insert(std::make_pair(45, "fourty five"));
myMap.insert(std::make_pair(-1, "minus one"));
std::multimap<int, std::string>::iterator iter = myMap.find(3);
if (iter != myMap.end()) {
myMap.erase(iter, iter++); //segmentation fault(!)
}
for (auto element : myMap) {
std::cout << element.first << " -> " << element.second << std::endl;
}
return 0;
}
我使用命令g++ --std=c++11 main.cpp
构建(我使用 g++ 5.2.1)。
为什么迭代器的后递增会导致分段错误?我宁愿说这应该创建此迭代器的 2 个副本,将它们传递到 erase 方法中,像代码一样"不擦除任何内容"myMap.erase(iter, iter);
然后递增iter
.
这个段错误背后有什么逻辑?
这是对迭代器的无效使用iter
吗?如果是这样 - 为什么?
顺便说一句。当我使用预递增myMap.erase(iter, ++iter)
时,它会编译,在这里它"不擦除任何内容",如上所述。
未定义函数调用参数的计算顺序。 所以当你写:
myMap.erase(iter, iter++); //segmentation fault(!)
编译器可以自由地先计算第二个参数,也可以不计算第二个参数。当您使用相同的迭代器但有副作用时,您会得到未定义的行为(请参阅C++标准,第 1.9/15 节)。
例如,如果编译器首先计算第二个参数iter++
,则递增的迭代器将用作第一个参数,而第二个参数不会递增iter
。结果:传递给 erase() 的范围将是[std::next(iter), iter)
- 该函数可能会尝试擦除超出范围的元素(即 UB)。
正如大卫在评论中建议的那样,您可以使用iter = myMap.erase(iter)
(或使用没有副作用的范围)来解决问题。
相关文章:
- 为什么 C++ std::unordered_map 从 emplace/ 找到返回一个迭代器?
- 为什么我的模板化函数需要从一个迭代器转换到另一个迭代器?
- 转到基于范围的 for 循环中的下一个迭代器
- 有没有一个迭代器的例子,它不会使用 ptrdiff_t 作为其difference_type?
- 每个花哨的指针都应该是一个迭代器吗?
- 如何使用find_if获取最后一个迭代器
- 为什么我无法在C++中将一个迭代器分配给另一个迭代器?
- 递增迭代器以指向另一个迭代器的下一个元素
- 使用一个迭代器迭代向量的向量
- 传入一个迭代器,该迭代器只迭代满足特定条件的元素
- 另一个迭代器引用的对象被另一个迭代器删除
- 使用给定的第一个和最后一个迭代器迭代范围
- 如何从给定另一个迭代器向量的向量中删除元素
- 如何寻址循环中的下一个迭代器并在同一地址插入元素
- 如何编写一个迭代器包装器来组合底层迭代器中的顺序值组
- 我正在尝试为我的 DynamicArray 类创建一个迭代器。为什么 STL 排序不适用于我的迭代器?
- 找到一个位置并返回一个迭代器不起作用
- 存储当前和下一个迭代器
- 谁应该有一个迭代器,我的数据类或该类中的实际列表
- 检查迭代器是否在另一个迭代器之前