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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:36:06  来源:igfitidea点击:

What is the difference between unordered_map :: emplace and unordered_map :: insert in C++?

c++c++11unordered-map

提问by Harsh M. Shah

What is the difference between std::unordered_map::emplaceand std::unordered_map::insertin C++?

在 C++ 中std::unordered_map::emplacestd::unordered_map::insert在 C++ 中有什么区别?

回答by Chris Drew

unordered_map::insertcopies 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::emplaceallows 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. emplacecan be used to forward to the copy/move constructor of the key-value pair which allows it to be used just as insertwould. This means that use of emplacedoesn't guarantee you will avoid copies or moves. Also the version of insertthat takes an rvalue-reference is actually templated and accepts any type Psuch that the key-value pair is constructible from P.

但是这两个功能之间存在大量重叠。emplace可用于转发到键值对的复制/移动构造函数,这允许它按原样使用insert。这意味着使用emplace并不能保证您将避免复制或移动。此外insert,采用 rvalue-reference的版本实际上是模板化的,并接受任何类型P,以便键值对可以从P.

Scott Meyers says:

斯科特·迈耶斯 说:

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 insertis faster than emplace)

编辑:Howard Hinnant 进行了一些实验,结果显示有时insert比 更快emplace

If you definitely do want to copy/move into the container it might be wise to use insertbecause 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::emplacewill cause memory to be dynamically allocated for the new pair even if the map contains an item with that key already and the emplacewill fail. This means that if there is a good chance that an emplacewill 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::emplacewith a key or value that takes more than one constructor parameter. Using the std::pairpiecewise 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
}