🥧
コンテナに効率よくデータを追加するemplace()
std::map
やstd::vector
のようなコンテナに要素を追加する際、普通はinsert()
やpush_back()
を使うと思いますが、emplace()
やemplace_back()
を使ったことありますか?
#include <string>
struct Person
{
std::string name;
std::string country;
int age;
};
std::vector
に上記の構造体の新しいインスタンスを追加したいとしましょう。
#include <vector>
std::vector<Person> people;
people.insert(people.begin(), {"Yamada Taro", "Japan", 30});
people.push_back({"Yamada Taro", "Japan", 30});
// vs.
people.emplace(people.begin(), "Yamada Taro", "Japan", 30);
people.emplace_back("Yamada Taro", "Japan", 30);
-
insert()
やpush_back()
の場合は、まずはPerson
のインスタンスを作ってから渡すため、そのインスタンスがコンテナにコピーかムーブされます。 -
emplace()
やemplace_back()
の場合は、Person
のコンストラクタに渡したい引数を指定すると、インスタンスを直接コンテナの中で作ってくれるため、コピーやムーブは不要になります。
もちろんパフォーマンス的にemplace()
やemplace_back()
の方がいいですね。
パフォーマンスと関係ないユースケースも紹介しましょう。
例えばPerson
を以下のようにコピーとムーブ出来ないようにしてからstd::map
に追加したい場合は、insert
はコピーかムーブが必要になるせいで使えなくなり、そのコンテナの中で直接作るemplace()
を使わないといけなくなります。
#include <map>
struct Person
{
std::string name;
std::string country;
int age;
Person(std::string _name, std::string _country, int _age)
: name(_name), country(_country), age(_age)
{};
Person(const Person&) = delete; // コピーコンストラクタを禁止する
Person(Person&&) = delete; // ムーブコンストラクタを禁止する
Person& operator=(const Person&) = delete; // コピー代入演算子を禁止する
Person& operator=(Person&&) = delete; // ムーブ代入演算子を禁止する
};
std::map<std::string, Person> people;
people.insert({"yamataro", {"Yamada Taro", "Japan", 30}}); // コンパイルエラー
people.emplace(std::piecewise_construct,
std::forward_as_tuple("yamataro"),
std::forward_as_tuple("Yamada Taro", "Japan", 30)); // OK
是非いつか使ってみてください。
Discussion