c++ emplace_back

概述

为了在容器操作时尽可能的减少构造函数的调用和内存的拷贝,C++11 引入了emplace_back的方法,该方法可以改善往容器内推入元素对象时的效率。相比push_back, push_front等成员函数,它可以节省一次拷贝构造函数的调用从而提高插入效率。

代码演示

#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); //没有类的创建

    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";
    }
}

执行结果

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.

结果分析

  从结果看,确实在调用emplace_back成员函数的时候少了一次拷贝构造函数或者移动构造函数。但是细心的朋友可以发现,emplace_back()成员函数调用的时候我们是直接用类的参数列表作为形参的(push_back不能这么使用,它必须接收现成的对象或者对象在指针),所以确实可以少一次拷贝构造函数。那么问题来了,如果我们要把一个已存在的对象推入容器时,会不会调用呢?

代码展示

int main()
{
    std::vector<President> elections;
    std::cout << "emplace_back:\n";
    //elections.emplace_back("Nelson Mandela", "South Africa", 1994); //没有类的创建
    //elections.emplace_back("Nelson Mandela", "South Africa", 1994); //没有类的创建

    President Nelson("Nelson Mandela", "South Africa", 1994);
    elections.emplace_back(Nelson); //拷贝构造函数

    std::cout << "\nemplace_back2:\n";
    elections.emplace_back(President("Joseph Robinette Biden", "US", 2021)); //构造,移动构造,拷贝构造函数


    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";
    }
}

结果展示

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.

结果分析

  从结果可以看出当我们推入一个已经存在的对象时push_back()和emplace_back()的表现完全一样都要去调用拷贝构造函数。当让临时对象作为形参推入容器时两者表现也完全一样,都要调用拷贝,移动,拷贝构造函数。

总结

  emplace_back()之所以可能提高效率时因为其提供了可以直接输入类参数列表的功能,可以直接在容器内部新建这个对象。而push_back(),push_front()等函数不具备这个凡尔赛功能。

当然如果我们想提高效率时,也可以让容器变为指针容器,到时候直接推入指针变量即可。这样的话,每次推入的代价就由真个类的的拷贝构造函数转为了指针的拷贝,效率会明显提升

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容