开发者社区> double2li> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

C++11使用emplace_back代替push_back

简介: 最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多。 首先,写了一个类用于计时, //time_interval.
+关注继续查看

最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多。

首先,写了一个类用于计时,

//time_interval.h
#pragma once

#include <iostream>
#include <memory>
#include <string>
#ifdef GCC
#include <sys/time.h>
#else
#include <ctime>
#endif // GCC

class TimeInterval
{
public:
    TimeInterval(const std::string& d) : detail(d)
    {
        init();
    }

    TimeInterval()
    {
        init();
    }

    ~TimeInterval()
    {
#ifdef GCC
        gettimeofday(&end, NULL);
        std::cout << detail 
            << 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000 
            << " ms" << endl;
#else
        end = clock();
        std::cout << detail 
            << (double)(end - start) << " ms" << std::endl;
#endif // GCC
    }

protected:
    void init() {
#ifdef GCC
        gettimeofday(&start, NULL);
#else
        start = clock();
#endif // GCC
    }
private:
    std::string detail;
#ifdef GCC
    timeval start, end;
#else
    clock_t start, end;
#endif // GCC
};

#define TIME_INTERVAL_SCOPE(d)   std::shared_ptr<TimeInterval> time_interval_scope_begin = std::make_shared<TimeInterval>(d)

 

使用方法就是在作用域中使用宏TIME_INTERVAL_SCOPE(d),d为打印用的字符串,输出作用域的耗时情况。

其次,看一下现在push到vector的5种方法的耗时情况对比:

#include <vector>
#include <string>
#include "time_interval.h"

int main() {


    std::vector<std::string> v;
    int count = 10000000;
    v.reserve(count);       //预分配十万大小,排除掉分配内存的时间

    {
        TIME_INTERVAL_SCOPE("push_back string:");
        for (int i = 0; i < count; i++)
        {
            std::string temp("ceshi");
            v.push_back(temp);// push_back(const string&),参数是左值引用
        }
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("push_back move(string):");
        for (int i = 0; i < count; i++)
        {
            std::string temp("ceshi");
            v.push_back(std::move(temp));// push_back(string &&), 参数是右值引用
        }
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("push_back(string):");
        for (int i = 0; i < count; i++)
        {
            v.push_back(std::string("ceshi"));// push_back(string &&), 参数是右值引用
        }
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("push_back(c string):");
        for (int i = 0; i < count; i++)
        {
            v.push_back("ceshi");// push_back(string &&), 参数是右值引用
        }
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("emplace_back(c string):");
        for (int i = 0; i < count; i++)
        {
            v.emplace_back("ceshi");// 只有一次构造函数,不调用拷贝构造函数,速度最快
        }
    }
}

 

vs2015 release下编译,运行结果:

push_back string:327 ms 
push_back move(string):213 ms 
push_back(string):229 ms 
push_back(c string):215 ms 
emplace_back(c string):122 ms

第1中方法耗时最长,原因显而易见,将调用左值引用的push_back,且将会调用一次string的拷贝构造函数,比较耗时,这里的string还算很短的,如果很长的话,差异会更大

第2、3、4中方法耗时基本一样,参数为右值,将调用右值引用的push_back,故调用string的移动构造函数,移动构造函数耗时比拷贝构造函数少,因为不需要重新分配内存空间。

第5中方法耗时最少,因为emplace_back只调用构造函数,没有移动构造函数,也没有拷贝构造函数。

为了证实上述论断,我们自定义一个类,并在普通构造函数、拷贝构造函数、移动构造函数中打印相应描述:

#include <vector>
#include <string>
#include "time_interval.h"

class Foo {
public:
    Foo(std::string str) : name(str) {
        std::cout << "constructor" << std::endl;
    }
    Foo(const Foo& f) : name(f.name) {
        std::cout << "copy constructor" << std::endl;
    }
    Foo(Foo&& f) : name(std::move(f.name)){
        std::cout << "move constructor" << std::endl;
    }

private:
    std::string name;
};
int main() {


    std::vector<Foo> v;
    int count = 10000000;
    v.reserve(count);       //预分配十万大小,排除掉分配内存的时间

    {
        TIME_INTERVAL_SCOPE("push_back T:");
        Foo temp("ceshi");
        v.push_back(temp);// push_back(const T&),参数是左值引用
        //打印结果:
        //constructor
        //copy constructor
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("push_back move(T):");
        Foo temp("ceshi");
        v.push_back(std::move(temp));// push_back(T &&), 参数是右值引用
        //打印结果:
        //constructor
        //move constructor
    }

    v.clear();
    {
        TIME_INTERVAL_SCOPE("push_back(T&&):");
        v.push_back(Foo("ceshi"));// push_back(T &&), 参数是右值引用
        //打印结果:
        //constructor
        //move constructor
    }

    v.clear();
    {
        std::string temp = "ceshi";
        TIME_INTERVAL_SCOPE("push_back(string):");
        v.push_back(temp);// push_back(T &&), 参数是右值引用
        //打印结果:
        //constructor
        //move constructor
    }

    v.clear();
    {
        std::string temp = "ceshi";
        TIME_INTERVAL_SCOPE("emplace_back(string):");
        v.emplace_back(temp);// 只有一次构造函数,不调用拷贝构造函数,速度最快
        //打印结果:
        //constructor
    }
}

 

结论:在C++11情况下,果断用emplace_back代替push_back

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
C++中push_back和emplace_back的区别
在 `C++11` 之后,`vector` 容器中添加了新的方法:`emplace_back()` ,和 `push_back()` 一样的是都是在容器末尾添加一个新的元素进去,不同的是 `emplace_back()` 在效率上相比较于 `push_back()` 有了一定的提升。
0 0
Push or Pull?
采用Pull模型还是Push模型是很多中间件都会面临的一个问题。消息中间件、配置管理中心等都会需要考虑Client和Server之间的交互采用哪种模型: 服务端主动推送数据给客户端? 客户端主动从服务端拉取数据? 本篇文章对比Pull和Push,结合消息中间件的场景进一步探讨有没有其他更合适的模型。
788 0
数组中的push()和pop()方法
push()方法可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。 pop()方法是从数组末尾移除最后一项,减小数组的length值,然后返回移除的项。 var arr = []; var count = arr.
464 0
push_back模式工作
自己决心今天做一个 xxx项目,写完xxx功能。 早晨9点多张三说:“A项目有一个 bug要修复”,估计十分钟就修复了,然后放弃手头项目去搞。修复这个bug的时候,发现这个A项目有些代码还有可以优化的地方,于是开始搞优化,优化完又测试。
504 0
emplace_back与push_back的区别
std::vector::emplace_back     C++   Containers library   std::vector   templatevoid emplace_back( Args&&.
1066 0
Come Back!
上次写blog到现在已经有段时间了,未免有些惭愧,工作也已四年左右了,技术、业务、人际关系等方面都有了与学校中不同的体会,有好的,有坏的,有期许,也有无奈,自己不能再这样沉沦,从现在开始要更加努力,恢复至少在学校的动力与激情,从blog开始,加油!...
454 0
back track
引用:http://baike.baidu.com/view/1627379.htm 1. 简介   BackTrack经过了多年发展,渗透测试并接受来自安全社区前所未有的帮助。BackTrack开始于早期live linux的发行版Whoppix,IWHAX以及auditor。
985 0
演示STL双端队列的push_back和push_front函数
双端队列(deque)和向量没有多少区别。它们主要的区别在性能上:和向量相比,在双端队列起点上的插入和删除操作要快的多,其时间复杂度仅为常数。所有的STL类属方法都可用于双端队列。下面为push_back和push_front函数的列子: 1 #include 2 #include ...
588 0
+关注
double2li
一个在IT行业摸爬滚打的老司机
文章
问答
文章排行榜
最热
最新
相关电子书
更多
使用C++开发PHP7扩展
立即下载
GPON Class C++ SFP O;T Transce
立即下载
使用C++11开发PHP7扩展
立即下载