调用associative container的insert(InputIt first, InputIt last)时,迭代器指向自身容器的行为疑问
调用associative container的insert(InputIt first, InputIt last)时,迭代器指向自身容器的行为疑问
这个问题问得很典型,咱们一步步拆解来看:
首先还原你的代码和现象:
std::unordered_multiset<int> set({1, 2}); set.insert(set.begin(), set.end()); for(int x: set) std::cout << x << ' ';
这段代码输出了1 2 2,但你预期应该是1 1 2 2的某种排列,疑惑这是未定义行为还是实现bug,而且没在标准里找到该函数的前置条件。
问题根源:无序容器的迭代器失效特性
你这里使用的是unordered_multiset这类无序关联容器,它有一个关键特性:当插入元素导致容器的负载因子超过阈值时,会触发rehash(重新哈希)操作,此时容器内的所有迭代器都会失效。
而你调用的insert(first, last)是范围插入,它的逻辑是遍历first到last的每个元素,逐个插入到容器中。当你传入的迭代器指向当前容器本身时,就会出现致命问题:
- 插入第一个元素后,容器可能已经触发了rehash,原来的
begin()和end()迭代器直接失效; - 后续基于失效迭代器的遍历行为完全是未定义的——可能提前终止遍历(就像你看到的只插入了一个额外元素)、可能插入重复内容、甚至程序崩溃。
关于标准的说明
虽然标准没有把“输入迭代器不能指向自身容器”直接写在insert的前置条件里,但这是由无序容器的迭代器特性推导出来的隐含要求:范围插入依赖迭代器在整个遍历过程中保持有效,如果迭代器指向正在被修改的容器,一旦插入操作导致迭代器失效,后续操作就失去了合法基础,自然属于未定义行为。
结论
这不是实现的bug,而是未定义行为,原因是你使用了指向自身容器的迭代器范围执行插入操作,违反了无序容器迭代器的使用规则。
备注:内容来源于stack exchange,提问作者Lassie
相关产品推荐
相关产品推荐

