C++ 中 unordered_map :: emplace 和 unordered_map :: insert 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26446352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between unordered_map :: emplace and unordered_map :: insert in C++?
提问by Harsh M. Shah
What is the difference between std::unordered_map::emplace
and std::unordered_map::insert
in C++?
在 C++ 中std::unordered_map::emplace
和std::unordered_map::insert
在 C++ 中有什么区别?
回答by Chris Drew
unordered_map::insert
copies or moves a key-value pair into the container. It is overloaded to accept reference-to-const or an rvalue reference:
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
allows you to avoid unnecessary copies or moves by constructing the element in place. It uses perfect forwarding and a variadic template to forward arguments to the constructor of the key-value pair:
unordered_map::emplace
允许您通过在位构建元素来避免不必要的复制或移动。它使用完美转发和可变参数模板将参数转发给键值对的构造函数:
template<class... Args>
std::pair<iterator,bool> emplace(Args&&... args);
But there is a great deal of overlap between the two functions. emplace
can be used to forward to the copy/move constructor of the key-value pair which allows it to be used just as insert
would. This means that use of emplace
doesn't guarantee you will avoid copies or moves. Also the version of insert
that takes an rvalue-reference is actually templated and accepts any type P
such that the key-value pair is constructible from P
.
但是这两个功能之间存在大量重叠。emplace
可用于转发到键值对的复制/移动构造函数,这允许它按原样使用insert
。这意味着使用emplace
并不能保证您将避免复制或移动。此外insert
,采用 rvalue-reference的版本实际上是模板化的,并接受任何类型P
,以便键值对可以从P
.
In principle, emplacement functions should sometimes be more efficient than their insertion counterparts, and they should never be less efficient.
原则上,定位函数有时应该比插入函数更有效,而且它们的效率永远不低。
( Edit:Howard Hinnant ran some experimentsthat showed sometimes insert
is faster than emplace
)
(编辑:Howard Hinnant 进行了一些实验,结果显示有时insert
比 更快emplace
)
If you definitely do want to copy/move into the container it might be wise to use insert
because you are more likely to get a compilation error if you pass incorrect arguments. You need to be more careful you are passing the correct arguments to the emplacement functions.
如果您确实想复制/移动到容器中,那么使用它可能是明智的,insert
因为如果传递不正确的参数,您更有可能得到编译错误。您需要更加小心,将正确的参数传递给定位函数。
Most implementations of unordered_map::emplace
will cause memory to be dynamically allocated for the new pair even if the map contains an item with that key already and the emplace
will fail. This means that if there is a good chance that an emplace
will fail you may get better performance using insert to avoid unneccessary dynamic memory allocations.
的大多数实现unordered_map::emplace
都会导致为新对动态分配内存,即使映射包含具有该键的项目并且emplace
会失败。这意味着如果 anemplace
失败的可能性很大,您可以使用 insert 获得更好的性能,以避免不必要的动态内存分配。
Small example:
小例子:
#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";
}
Edit2:On request. It is also possible to use unordered_map::emplace
with a key or value that takes more than one constructor parameter. Using the std::pair
piecewise constructoryou can still avoid unnecessary copies or moves.
编辑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
}