文章目录
我们以STL中的vector
容器为例。我们来看看这两个函数的原型:
然后我们用一段代码来看看执行这两个函数时的过程:
#include<iostream>
#include <vector>
using namespace std;
class MyTest
{
public:
//普通构造
MyTest(int id,int age):m_id(id),m_age(age)
{
cout << "ceate MyTest class..." << this << endl;
}
//拷贝构造
MyTest(const MyTest &t):m_id(t.m_id),m_age(t.m_age)
{
cout << "copy construct called..." << this << endl;
}
//移动构造
MyTest(const MyTest &&t)
{
m_id = std::move(t.m_id);
m_age = std::move(t.m_age);
cout << "move contruct called.." << this << endl;
}
//析构
~MyTest()
{
cout << "destory MyTest class..." << this << endl;
}
private:
int m_id; //id成员
int m_age;//age成员
};
过程对比
首先我们先总结它们的效率对比
- 内置类型(built-in type):都一样
- 用户自定义的类(User-defined type):emplace_pack仅在通过使用构造参数传入的时候更高效!
1.通过构造参数向vector中插入对象(emplace_back更高效)
2.通过插入实例对象(调用copy函数)
3.通过插入临时对象(调用move函数)
效率对比
同样是在容器尾部增加一个元素,emplace_back 比 push_back 少了一次对象的构造和析构, 所以,emplace_back 比 push_back 更高效, 具体能高效多少呢,这里进行了一个插入 一百万 个对象的测试,emplace_back 比 push_back 快大概 20% ,下面是测试代码 :
//获取当前时间,单位: 毫秒
int64_t cur_msec()
{
struct timespec tp1;
clock_gettime(CLOCK_REALTIME, &tp1);
return (tp1.tv_sec * 1000 + (int64_t)tp1.tv_nsec / 1000000.0);
}
//测试函数
void test()
{
vector<MyTest> vec1;
vector<MyTest> vec2;
vec1.reserve(1000000);
vec2.reserve(1000000);
int64_t t1 = cur_msec();
for (size_t i = 0; i < 1000000; i++)
{
vec1.push_back(MyTest(1,20));
}
int64_t t2 = cur_msec();
for (size_t i = 0; i < 1000000; i++)
{
vec2.emplace_back(1,20);
}
int64_t t3 = cur_msec();
cout << " push_back cost " << (t2 - t1) << " millisecond " << endl;
cout << " emplace_back cost " << (t3 - t2) << " millisecond " << endl;
}
emplace_back 的缺点
既然 emplace_back 比 push_back 更高效,是不是每次都用 emplace_back 就完了呢?
我们日常写代码,除了执行率之外,还要考虑可读性,理解成本等,虽然emplace_back 效率高些,但是它也是有缺点的,比如:
vec1.push_back(1000000);
vec2.emplace_back(1000000);
第一行程序代码很好理解,往 容器vec1尾部加入一个整数 1000000,然而,第二行程序代码就不是很直观了,由于我们不知道 vec2 的实际类型,所以无法获得这行代码执行的结果。
假如,vec2 的类型是 vector,那么它的含义和第一行一样,往容器vec2尾部添加整数 1000000。
假如,vec2 的类型是 vector< vector >,那么它就构造了一个包含 1000000 个元素的容器,按照每个元素 4 个字节来计算,执行第二行代码需要分配差不多近 4M 的内存空间。