C++11 中, 针对顺序容器 (如 vector,deque,list), 新标准引入了三个新成员: emplace_front,emplace 和 emplace_back, 这些操作构造而不是拷贝元素. 这些操作分别对应 push_front,insert 和 push_back, 允许我们将元素放置在容器头部, 一个指定位置之前或容器尾部.
当调用 push 或 insert 成员函数时, 我们将元素类型的对象传递给它们, 这些对象被拷贝到容器中. 而当我们调用一个 emplace 成员函数时, 则是将参数传递给元素类型的构造函数. emplace 成员使用这些参数在容器管理的内存空间中直接构造元素.
emplace 函数的参数根据元素类型而变化, 参数必须与元素类型的构造函数相匹配. emplace 函数在容器中直接构造元素. 传递给 emplace 函数的参数必须与元素类型的构造函数相匹配.
其它容器中, std::forward_list 中的 emplace_after,emplace_front 函数, std::map/std::multimap 中的 emplace,emplace_hint 函数, std::set/std::multiset 中的 emplace,emplace_hint,std::stack 中的 emplace 函数, 等 emplace 相似函数操作也均是构造而不是拷贝元素.
emplace 相关函数可以减少内存拷贝和移动. 当插入 rvalue, 它节约了一次 move 构造, 当插入 lvalue, 它节约了一次 copy 构造.
下面是从其他文章中 copy 的测试代码, 详细内容介绍可以参考对应的 reference:
- #include "emplace.hpp"
- #include <iostream>
- #include <vector>
- #include <string>
- #include <map>
- #include <tuple>
- #include <utility>
- namespace emplace_ {
- /////////////////////////////////////////////////////////
- // reference: http://www.cplusplus.com/reference/vector/vector/emplace_back/
- int test_emplace_1()
- {
- {
- /*
- template <class... Args>
- void emplace_back (Args&&... args);
- */
- std::vector<int> myvector = { 10, 20, 30 };
- myvector.emplace_back(100);
- myvector.emplace_back(200);
- std::cout <<"myvector contains:";
- for (auto& x : myvector)
- std::cout << ' ' << x;
- std::cout << '\n';
- }
- {
- /*
- template <class... Args>
- iterator emplace (const_iterator position, Args&&... args);
- */
- std::vector<int> myvector = { 10, 20, 30 };
- auto it = myvector.emplace(myvector.begin() + 1, 100);
- myvector.emplace(it, 200);
- myvector.emplace(myvector.end(), 300);
- std::cout <<"myvector contains:";
- for (auto& x : myvector)
- std::cout << ' ' << x;
- std::cout << '\n';
- }
- return 0;
- }
- ///////////////////////////////////////////////////////
- // reference: http://en.cppreference.com/w/cpp/container/vector/emplace_back
- namespace {
- struct President {
- std::string name;
- std::string country;
- int year;
- President(std::string p_name, std::string p_country, int p_year)
- : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
- {
- std::cout << "I am being constructed.\n";
- }
- President(President&& other)
- : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
- {
- std::cout << "I am being moved.\n";
- }
- President& operator=(const President& other) = default;
- };
- }
- int test_emplace_2()
- {
- /*
- The following code uses emplace_back to append an object of type President to a std::vector.
- It demonstrates how emplace_back forwards parameters to the President constructor and shows
- how using emplace_back avoids the extra copy or move operation required when using push_back.
- */
- std::vector<President> elections;
- std::cout <<"emplace_back:\n";
- elections.emplace_back("Nelson Mandela", "South Africa", 1994);
- std::vector<President> reElections;
- std::cout <<"\npush_back:\n";
- reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
- std::cout << "\nContents:\n";
- for (President const& president : elections) {
- std::cout << president.name << "was elected president of"
- << president.country << "in" << president.year << ".\n";
- }
- for (President const& president : reElections) {
- std::cout << president.name << "was re-elected president of"
- << president.country << "in" << president.year << ".\n";
- }
- return 0;
- }
- ////////////////////////////////////////////////////////////////
- // reference: https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back
- int test_emplace_3()
- {
- /*
- template <class... Args>
- pair<iterator,bool> emplace (Args&&... args);
- */
- typedef std::tuple<int, double, std::string> Complicated;
- std::map<int, Complicated> m;
- int anInt = 4;
- double aDouble = 5.0;
- std::string aString = "C++";
- // cross your finger so that the optimizer is really good
- //m.insert(/*std::make_pair*/std::pair<int, Complicated>(4, Complicated(anInt, aDouble, aString)));
- m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
- // should be easier for the optimizer
- m.emplace(6, Complicated(anInt, aDouble, aString));
- /*
- std::piecewise_construct: This constant value is passed as the first argument to construct a pair object
- to select the constructor form that constructs its members in place by forwarding the elements of two
- tuple objects to their respective constructor.
- */
- m.emplace(std::piecewise_construct, std::make_tuple(8), std::make_tuple(anInt, aDouble, aString));
- return 0;
- }
- //////////////////////////////////////////////////////////////
- // reference: https://corecplusplustutorial.com/difference-between-emplace_back-and-push_back-function/
- namespace {
- class Dat {
- int i;
- std::string ss;
- char c;
- public:
- Dat(int ii, std::string s, char cc) :i(ii), ss(s), c(cc) { }
- ~Dat() { }
- };
- }
- int test_emplace_4()
- {
- std::vector<Dat> vec;
- vec.reserve(3);
- vec.push_back(Dat(89, "New", 'G')); // efficiency lesser
- //vec.push_back(678, "Newer", 'O'); // error,push_back can't accept three arguments
- vec.emplace_back(890, "Newest", 'D'); // work fine, efficiency is also more
- return 0;
- }
- } // namespace emplace_
来源: http://www.bubuko.com/infodetail-2882345.html