49

C++のstd::unordered_map::emplaceとの違いは何ですか?std::unordered_map::insert

4

2 に答える 2

63

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);

しかし、2 つの機能には多くの重複があります。emplaceキーと値のペアのコピー/移動コンストラクターに転送するために使用できます。これにより、キーと値のペアをそのまま使用できますinsert。これは、 を使用しemplaceても、コピーや移動を回避できるとは限らないことを意味します。また、右辺値参照を取る のバージョンはinsert、実際にはテンプレート化Pされており、 からキーと値のペアを構築できるような任意の型を受け入れますP

スコット・マイヤーズ 言います:

原則として、埋め込み関数は対応する挿入関数よりも効率的である必要があり、効率が低下することはありません。

(編集:ハワード・ヒナントはいくつかの実験insertを行い、が よりも速い場合があることを示しましたemplace)

確実にコンテナーにコピー/移動したい場合はinsert、間違った引数を渡すとコンパイル エラーが発生する可能性が高くなるため、使用するのが賢明かもしれません。配置関数に正しい引数を渡すように注意する必要があります。

のほとんどの実装でunordered_map::emplaceは、マップにそのキーを持つアイテムが既に含まれている場合でも、メモリが新しいペアに動的に割り当てられ、emplaceは失敗します。これは、emplaceが失敗する可能性が高い場合、挿入を使用してパフォーマンスを向上させ、不要な動的メモリ割り当てを回避できることを意味します。

小さな例:

#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:リクエストに応じて。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
}
于 2014-10-19T03:34:12.147 に答える