在C++中,unordered_map::template和unordered_map::insert之间有什么区别
What is the difference between unordered_map::emplace and unordered_map::insert in C++?
C++中的std::unordered_map::emplace
和std::unordered_map::insert
之间有什么区别?
unordered_map::insert
将键值对复制或移动到容器中。它被重载以接受对常量或右值引用的引用:
std::pair<iterator,bool> insert(const std::pair<const Key, T>& value);
template<class P>
std::pair<iterator,bool> insert(P&& value);
unordered_map::emplace
允许您通过就地构建元素来避免不必要的复制或移动。它使用完美转发和可变模板将参数转发到键值对的构造函数:
template<class... Args>
std::pair<iterator,bool> emplace(Args&&... args);
但这两种功能之间有很大的重叠。emplace
可以用于转发到键值对的复制/移动构造函数,这允许它像insert
一样被使用。这意味着使用emplace
并不能保证您可以避免复制或移动。此外,采用右值引用的insert
版本实际上是模板化的,并接受任何类型的P
,使得键值对可以从P
构造。
Scott Meyers说:
原则上,安置职能有时应该更有效率与插入对应项相比,它们永远不应该少有效率的
(编辑:Howard Hinnant进行了一些实验,表明有时insert
比emplace
快)
如果您确实想复制/移动到容器中,那么使用insert
可能是明智的,因为如果传递不正确的参数,则更有可能出现编译错误。在将正确的参数传递给安置函数时,您需要更加小心。
unordered_map::emplace
的大多数实现将导致为新对动态分配内存,即使映射已经包含具有该密钥的项并且emplace
将失败。这意味着,如果emplace
很有可能失败,那么使用insert可以获得更好的性能,以避免不必要的动态内存分配。
小示例:
#include <unordered_map>
#include <iostream>
int main() {
auto employee1 = std::pair<int, std::string>{1, "John Smith"};
auto employees = std::unordered_map<int, std::string>{};
employees.insert(employee1); // copy insertion
employees.insert(std::make_pair(2, "Mary Jones")); // move insertion
employees.emplace(3, "James Brown"); // construct in-place
for (const auto& employee : employees)
std::cout << employee.first << ": " << employee.second << "n";
}
第2版:应要求。也可以将unordered_map::emplace
与采用多个构造函数参数的键或值一起使用。使用std::pair
分段构造函数,您仍然可以避免不必要的复制或移动。
#include <unordered_map>
#include <iostream>
struct Employee {
std::string firstname;
std::string lastname;
Employee(const std::string& firstname, const std::string& lastname)
: firstname(firstname), lastname(lastname){}
};
int main() {
auto employees = std::unordered_map<int, Employee>{};
auto employee1 = std::pair<int, Employee>{1, Employee{"John", "Smith"}};
employees.insert(employee1); // copy insertion
employees.insert(std::make_pair(2, Employee{"Mary", "Jones"})); // move insertion
employees.emplace(3, Employee("Sam", "Thomas")); // emplace with pre-constructed Employee
employees.emplace(std::piecewise_construct,
std::forward_as_tuple(4),
std::forward_as_tuple("James", "Brown")); // construct in-place
}
Chris Drew的回答中已经很好地解释了emplace()
和insert()
之间的区别。然而,为了完整起见,我想补充一点,因为C++17 std::unordered_map
提供了两种新的插入方法:try_emplace()
和insert_or_assign()
。让我简单总结一下这些方法:
- CCD_ 24是一个";改进的";CCD_ 25版本。与
emplace()
相反,如果由于unordered_map
中已经存在密钥而导致插入失败,try_emplace()
不会修改其参数(由于移动操作) - CCD_ 29是一个";改进的";CCD_ 30版本。和
operator[]
不同,insert_or_assign()
不要求unordered_map
的值类型是默认可构造的
我在这里为std::map
写了一个关于上述新插入方法的更详细的答案。这个答案也适用于std::unordered_map
。
Coliru 上的简单示例代码
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 使用一个考虑到std::map中键值的滚动或换行的键
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 允许从 std::map 的密钥窃取资源?
- 有没有办法对std::unordered_set、std::unrdered_map、std::set、std::map
- 将重物插入std::map
- 使用通用值初始化 std::map,不重复
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- C++:当所有条目都保证是唯一时,替代 std::map
- 使用模板化的键类型定义 std::map,该键类型基于作为参数接收的函数
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?
- 使用字符数组作为 Map 中的键
- C++如何创建 std::map
- C++ equivalent to Java Map getOrDefault?
- 从其他容器中移动构造"std::map"
- 如何使用 uint64_t 键类型从 std::map<int, std::string> 返回值?
- 将 std::map::emplace 与返回 shared_ptr 的函数一起使用是否正确?
- C++中 std::map 的运行时复杂度是多少?
- unordered map -在c++ std::unordered_map中预分配桶