博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)C++11使用emplace_back代替push_back (其中有关于右值引用)
阅读量:6454 次
发布时间:2019-06-23

本文共 9685 字,大约阅读时间需要 32 分钟。

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

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

//time_interval.h#pragma once#include 
#include
#include
#ifdef GCC#include
#else#include
#endif // GCCclass 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
time_interval_scope_begin = std::make_shared
(d)

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

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

#include 
#include
#include "time_interval.h"int main() { std::vector
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 
#include
#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
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中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多。

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

//time_interval.h#pragma once#include 
#include
#include
#ifdef GCC#include
#else#include
#endif // GCCclass 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
time_interval_scope_begin = std::make_shared
(d)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

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

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

#include 
#include
#include "time_interval.h"int main() { std::vector
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");// 只有一次构造函数,不调用拷贝构造函数,速度最快 } }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

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 
#include
#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
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 }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

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

转载于:https://www.cnblogs.com/wangshaowei/p/8867656.html

你可能感兴趣的文章
ASP.Net MVC的开发模式
查看>>
groupbox 下的datagridview的列标题字体修改混乱
查看>>
HDU-3092 Least common multiple---数论+分组背包
查看>>
CentOS 7使用systemctl如何补全服务名称
查看>>
Unity3D NGUI 给button按钮添加单间事件
查看>>
C# 使用各种API
查看>>
密码的校验.大小写字母,数字,特殊字符中的至少3种
查看>>
ios 不同sdk4.3 6.0版本号,关于方法的兼容性的通用方法
查看>>
Shell编程学习总结
查看>>
070、如何定制Calico 网络policy(2019-04-15 周一)
查看>>
构建之法阅读笔记02
查看>>
Webstorm常用快捷键备忘
查看>>
js滚动加载到底部
查看>>
关于mac远程链接window服务器以及实现共享文件
查看>>
Redis慢查询,redis-cli,redis-benchmark,info
查看>>
Virtualbox 虚拟机网络不通
查看>>
java概念基础笔记整理
查看>>
self parent $this关键字分析--PHP
查看>>
CC_UNUSED_PARAM 宏含义的解释
查看>>
leetcode124二叉树最大路径和
查看>>