为什么std::map的emplace方法不支持传入begin和end迭代器参数?
问题解答
接口差异原因
std::map的insert和emplace接口的设计定位完全不同:
insert的核心功能是插入已存在的元素/元素序列,标准库原生提供了接收[first, last)迭代器范围的重载,支持把范围内的所有元素批量插入到容器中。emplace是C++11新增的原地构造接口,设计初衷是直接向容器传入构造元素所需的参数,在容器的内存空间上直接构造目标元素,避免不必要的拷贝/移动开销,所以标准库没有为它设计接收迭代器范围的重载:迭代器指向的是已经构造完成的元素,和emplace接收构造参数的设计逻辑不匹配。
你代码中调用mp_.emplace(container.begin(), container.end())会编译报错,本质是因为你传入了两个迭代器作为参数,emplace会尝试用这两个迭代器构造一个std::pair<const T1, T2>对象,类型完全不匹配,自然编译失败。
实现方案
你手写循环的思路是可行的,但还有更简洁、性能更优的实现方式:
C++17及以上标准推荐方案
直接使用std::map的merge接口,直接转移源容器的节点,不需要对元素本身做任何移动/拷贝操作,性能最高:
void emplace(std::map<T1, T2>&& container) { mp_.merge(std::move(container)); }
C++11兼容方案
不需要手写循环,直接用std::make_move_iterator把迭代器包装成移动迭代器,交给insert接口即可,标准库会自动把源容器中的元素移动到目标容器中,性能和手写循环一致:
void emplace(std::map<T1, T2>&& container) { mp_.insert(std::make_move_iterator(container.begin()), std::make_move_iterator(container.end())); }
如果你坚持使用手写循环的实现,需要注意补充std::move,否则源容器的元素会被拷贝而非移动,达不到右值引用的性能收益:
for (auto&& ele : container) { mp_.emplace(std::move(ele)); }
内容的提问来源于stack exchange,提问作者Yves
相关产品推荐
相关产品推荐

