哪些场景应该用emplace_back

三月 14, 2022 [c++] #c++

哪些场景应该用emplace_back

emplace的插入原理

当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。
emplace函数的参数根据元素类型而变化,参数必须与元素类型的构造函数相匹配。emplace函数在容器中直接构造元素。传递给emplace函数的参数必须与元素类型的构造函数相匹配。
emplace相关函数可以减少内存拷贝和移动。当插入rvalue,它节约了一次move构造,当插入lvalue,它节约了一次copy构造。

#include<iostream>
#include<map>
#include<vector> 
using namespace std;
struct Test {
    int a;
    string b;
    Test(int _a, string _b):a(_a), b(_b){
        cout << "construct" << endl;
    }
    Test(const Test&& test):a(test.a), b(move(test.b)) {
        cout << "move" << endl;
    }
};

int main() {
    map<int, Test> m;
    int a = 0;
    string b = "test";
    cout << "--insert--" << endl;
    m.insert(make_pair(4, Test(a, b)));
    cout << "--emplace--" << endl;
    m.emplace(4, Test(a, b)); //通过构造函数参数直接构造对象 
    
    vector<Test> v;
    cout << "--push_back--" << endl;
    v.push_back(Test(a,b));
    cout << "--emplace_back--" << endl;
    v.emplace_back(a, b);
    
}
#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_

原文位置

https://www.jianshu.com/p/caad33287dc3
https://blog.csdn.net/fengbingchun/article/details/78670376
https://github.com/fengbingchun/Messy_Test