用作 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)。
为什么 post-我的迭代器的增量会导致分段错误?
我宁愿说这应该创建这个迭代器的 2 个副本,将它们传递给擦除方法,"erase nothing" 就像代码 myMap.erase(iter, iter);
一样,然后递增 iter
.
这个段错误背后的逻辑是什么?
这是对 iter
迭代器的无效使用吗?如果是 - 为什么?
顺便说一句。
当我使用预递增 myMap.erase(iter, ++iter)
时它会编译,这里是 "erase nothing" 如上所述。
函数调用参数的求值顺序未定义。所以当你写:
myMap.erase(iter, iter++); //segmentation fault(!)
编译器可以自由决定是否先计算第二个参数。当您使用相同的迭代器但有副作用时,您会得到未定义的行为(参考 C++ 标准,第 1.9/15 节)。
例如,如果编译器首先计算第二个参数 iter++
,递增的迭代器将用作第一个参数,而第二个参数不会递增 iter
。因此:传递给 erase() 的范围将是 [std::next(iter), iter)
- 该函数可能会尝试擦除超出范围的元素(即 UB)。
正如 David 在评论中所建议的那样,您可以使用 iter = myMap.erase(iter)
(或使用没有副作用的范围)来解决问题。
虽然 运行 一个显示如何从 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)。
为什么 post-我的迭代器的增量会导致分段错误?
我宁愿说这应该创建这个迭代器的 2 个副本,将它们传递给擦除方法,"erase nothing" 就像代码 myMap.erase(iter, iter);
一样,然后递增 iter
.
这个段错误背后的逻辑是什么?
这是对 iter
迭代器的无效使用吗?如果是 - 为什么?
顺便说一句。
当我使用预递增 myMap.erase(iter, ++iter)
时它会编译,这里是 "erase nothing" 如上所述。
函数调用参数的求值顺序未定义。所以当你写:
myMap.erase(iter, iter++); //segmentation fault(!)
编译器可以自由决定是否先计算第二个参数。当您使用相同的迭代器但有副作用时,您会得到未定义的行为(参考 C++ 标准,第 1.9/15 节)。
例如,如果编译器首先计算第二个参数 iter++
,递增的迭代器将用作第一个参数,而第二个参数不会递增 iter
。因此:传递给 erase() 的范围将是 [std::next(iter), iter)
- 该函数可能会尝试擦除超出范围的元素(即 UB)。
正如 David 在评论中所建议的那样,您可以使用 iter = myMap.erase(iter)
(或使用没有副作用的范围)来解决问题。