std::unordered_map::emplace
C++和C++有什么区别std::unordered_map::insert
?
2 回答
unordered_map::insert
将键值对复制或移动到容器中。它被重载以接受对 const 的引用或右值引用:
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
.
原则上,放置函数有时应该比插入函数更有效,而且它们的效率永远不应该降低。
(编辑: Howard Hinnant 进行了一些实验,结果显示有时insert
比 更快emplace
)
如果您确实想复制/移动到容器中,使用它可能是明智的,insert
因为如果您传递不正确的参数,您更有可能得到编译错误。您需要更加小心,您将正确的参数传递给 emplacement 函数。
的大多数实现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
}
emplace()
和之间的区别insert()
已经在Chris Drew 的回答中得到了很好的解释。但是,为了完整起见,我想补充一点,因为C++17 std::unordered_map
提供了两种新的插入方法:try_emplace()
和insert_or_assign()
. 让我简单总结一下这些方法:
try_emplace()
是 的“改进”版本emplace()
。与 相比emplace()
,try_emplace()
如果由于unordered_map
.insert_or_assign()
是 的“改进”版本operator[]
。与 相比operator[]
,insert_or_assign()
不需要 的值类型unordered_map
是默认可构造的。
std::map
我已经为here写了关于上述新插入方法的更详细的答案。该答案也适用于std::unordered_map
.