概述
為了在容器操作時(shí)盡可能的減少構(gòu)造函數(shù)的調(diào)用和內(nèi)存的拷貝,C++11 引入了emplace_back的方法乓序,該方法可以改善往容器內(nèi)推入元素對(duì)象時(shí)的效率丹鸿。相比push_back付鹿, push_front等成員函數(shù)蜜氨,它可以節(jié)省一次拷貝構(gòu)造函數(shù)的調(diào)用從而提高插入效率。
代碼演示
#include <iostream>
#include <string>
#include <vector>
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(const President& other)
: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
{
std::cout << "I am being copy 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);
};
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994); //沒有類的創(chuàng)建
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";
}
}
執(zhí)行結(jié)果
g++ emplace_back_push_back.cc --std=c++11
guanyunfei@ivan:~/practice/c++$ ./a.out
emplace_back:
I am being constructed.
push_back:
I am being constructed.
I am being moved.
Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.
結(jié)果分析
? 從結(jié)果看稠诲,確實(shí)在調(diào)用emplace_back成員函數(shù)的時(shí)候少了一次拷貝構(gòu)造函數(shù)或者移動(dòng)構(gòu)造函數(shù)侦鹏。但是細(xì)心的朋友可以發(fā)現(xiàn)诡曙,emplace_back()成員函數(shù)調(diào)用的時(shí)候我們是直接用類的參數(shù)列表作為形參的(push_back不能這么使用,它必須接收現(xiàn)成的對(duì)象或者對(duì)象在指針)略水,所以確實(shí)可以少一次拷貝構(gòu)造函數(shù)价卤。那么問題來了,如果我們要把一個(gè)已存在的對(duì)象推入容器時(shí)渊涝,會(huì)不會(huì)調(diào)用呢慎璧?
代碼展示
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
//elections.emplace_back("Nelson Mandela", "South Africa", 1994); //沒有類的創(chuàng)建
//elections.emplace_back("Nelson Mandela", "South Africa", 1994); //沒有類的創(chuàng)建
President Nelson("Nelson Mandela", "South Africa", 1994);
elections.emplace_back(Nelson); //拷貝構(gòu)造函數(shù)
std::cout << "\nemplace_back2:\n";
elections.emplace_back(President("Joseph Robinette Biden", "US", 2021)); //構(gòu)造,移動(dòng)構(gòu)造跨释,拷貝構(gòu)造函數(shù)
std::vector<President> reElections;
std::cout << "\npush_back:\n";
President Trump("Donald Trump", "US", 2016);
reElections.push_back(Trump);
std::cout << "\npush_back2:\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";
}
}
結(jié)果展示
emplace_back:
I am being constructed.
I am being copy constructed.
emplace_back2:
I am being constructed.
I am being moved.
I am being copy constructed.
push_back:
I am being constructed.
I am being copy constructed.
push_back2:
I am being constructed.
I am being moved.
I am being copy constructed.
Contents:
Nelson Mandela was elected president of South Africa in 1994.
Joseph Robinette Biden was elected president of US in 2021.
Donald Trump was re-elected president of US in 2016.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.
結(jié)果分析
? 從結(jié)果可以看出當(dāng)我們推入一個(gè)已經(jīng)存在的對(duì)象時(shí)push_back()和emplace_back()的表現(xiàn)完全一樣都要去調(diào)用拷貝構(gòu)造函數(shù)炸卑。當(dāng)讓臨時(shí)對(duì)象作為形參推入容器時(shí)兩者表現(xiàn)也完全一樣,都要調(diào)用拷貝煤傍,移動(dòng),拷貝構(gòu)造函數(shù)嘱蛋。
總結(jié)
? emplace_back()之所以可能提高效率時(shí)因?yàn)槠涮峁┝丝梢灾苯虞斎腩悈?shù)列表的功能蚯姆,可以直接在容器內(nèi)部新建這個(gè)對(duì)象。而push_back(),push_front()等函數(shù)不具備這個(gè)凡爾賽功能洒敏。
? 當(dāng)然如果我們想提高效率時(shí)龄恋,也可以讓容器變?yōu)橹羔樔萜鳎綍r(shí)候直接推入指針變量即可凶伙。這樣的話郭毕,每次推入的代價(jià)就由真?zhèn)€類的的拷貝構(gòu)造函數(shù)轉(zhuǎn)為了指針的拷貝,效率會(huì)明顯提升函荣。