1. 程式人生 > >c++11 vector使用emplace_back代替push_back

c++11 vector使用emplace_back代替push_back

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_