C++——Vector:push_back和emplace_back的区别,测试写入1GB大数据时的性能差距

什么是emplace_back

emplace_back是C++11引入的STL容器成员函数。emplace操作只执行构造而不执行拷贝构造。

如何理解上面这句话?先来看一个场景。

cpp 复制代码
class test
{
public:
    test(){}
    test(int i){ std::cout << "test(int i)" << std::endl; }
    test(const test& _test){ std::cout << "test(const test& _test)" << std::endl; }
};

int main()
{
    std::vector<test> arr;
    arr.reserve(5);

    arr.push_back(1);
    arr.emplace_back(1);

    return 0;
}

test类显式写出了三个构造函数,分别是无参构造、单参数构造、拷贝构造。因为C++中单参数的构造函数支持隐式类型转换,因此可以拿一个整型构造一个test对象。除非用explicit修饰构造函数,表示禁止隐式类型转换构造。

cpp 复制代码
test(int i)
test(const test& _test)
test(int i)

这是上述代码的运行结果,可以看到push_back中,会用整数1构造一个test对象,再通过拷贝构造再构造一个对象,这才是插入到arr数组中的对象。

而emplace_back只有一次隐式类型转换的构造,因为emplace是直接使用参数在容器管理的内存空间中直接构造元素,因此没有拷贝的操作,在一定程度上提高了效率。

写入大数据时的性能差异

cpp 复制代码
class test
{
public:
    test(){}
    test(int i){ }
    test(const test& _test){ }
};

void test_push_back()
{
    clock_t start = clock();
    std::vector<test> arr;
    arr.reserve(1000000000);

    for(int i = 0; i < 1000000000; i++)
    {
        arr.push_back(1);
    }

    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    /*
        耗时:24.41秒
    */
}

void test_emplace_back()
{
    clock_t start = clock();
    std::vector<test> arr;
    arr.reserve(1000000000);

    for(int i = 0; i < 1000000000; i++)
    {
        arr.emplace_back(1);
    }

    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    /*
        耗时:15.86秒
    */
}

int main()
{
    test_push_back();
    test_emplace_back();
    return 0;
}

shell脚本用于实时监控进程运行状况
while true; do ps aux | head -1 ; ps aux | grep a.out; printf "------------------------------------------------------------------\n\n" ; sleep 1; done

一个栈上的test对象的大小是1个字节,因为test类没有存储对象成员,而编译器为了表明一个test对象存在,需要用1字节作为占位符。

109 个对象即1亿个,1个对象是1个字节。后台检测到有982456个字节,即大约1GB。可以看到,插入109个test对象的时候,差距大概是10秒钟。

应用场景

你可能说,这种优化有什么用,有什么类会允许隐式类型转换,还可能插入的时候不显式构造?

没错,就是string。

cpp 复制代码
void test_push_back()
{
    clock_t start = clock();
    std::vector<std::string> arr;
    arr.reserve(1000000000);

    for(int i = 0; i < 100000000; i++)
    {
        arr.push_back("Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! ");
    }

    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    /*
        耗时:25.66秒
    */
}

void test_emplace_back()
{
    clock_t start = clock();
    std::vector<std::string> arr;
    arr.reserve(1000000000);

    for(int i = 0; i < 100000000; i++)
    {
        arr.emplace_back("Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! Hello World !!! ");
    }

    std::cout <<"耗时:"<< (clock() - start) << std::endl;
    /*
        耗时:16.20秒
    */
}
cpp 复制代码
耗时:20.39秒
耗时:17.87秒

可是差距好像并不是很大=-=

综上所述:可能提升有限,但是能使用emplace_back还是不使用push_back了。

相关推荐
Mr_WangAndy2 小时前
C++设计模式_结构型模式_组合模式Composite(树形模式)
c++·设计模式·组合模式
Miraitowa_cheems4 小时前
LeetCode算法日记 - Day 68: 猜数字大小II、矩阵中的最长递增路径
数据结构·算法·leetcode·职场和发展·贪心算法·矩阵·深度优先
希赛网4 小时前
软考软件设计师常考知识点:(三)数据结构
数据结构·二叉树·字符串·软考·软件设计师·线性表
·心猿意码·7 小时前
C++右值语义解析
开发语言·c++
小龙报7 小时前
《彻底理解C语言指针全攻略(2)》
c语言·开发语言·c++·visualstudio·github·学习方法
zzzsde8 小时前
【c++】深入理解string类(4)
开发语言·c++
少许极端9 小时前
算法奇妙屋(五)-链表
数据结构·算法·链表
木子.李3479 小时前
数据结构-算法C++(额外问题汇总)
数据结构·c++·算法
yolo_guo9 小时前
sqlite 使用: 03-问题记录:在使用 sqlite3_bind_text 中设置 SQLITE_STATIC 参数时,处理不当造成的字符乱码
linux·c++·sqlite
程序员莫小特10 小时前
老题新解|计算2的N次方
开发语言·数据结构·算法·青少年编程·信息学奥赛一本通