違いは何ですか std::unordered_map::emplace
およびstd::unordered_map::insert
C++で?
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
を受け入れます。
原則として、埋め込み関数は挿入関数よりも効率的である場合があり、効率が低下することはありません。
(Edit:Howard Hinnant ran 一部の実験 時折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
piecewise constructor を使用すると、不要なコピーや移動を回避できます。
#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
}