std::vector的emplace_back 与 push_back 比较

现在来对比一下emplace_backpush_back的区别,分别对有移动构造函数移动赋值运算符以及没有这两个函数的对象进行比较

1.没有 移动构造函数移动赋值运算符
class Test
{
public:
    Test()
    {
        qDebug() << "construct test" << this;
    }
    Test (const Test& other)
    {
        qDebug() << "copy construct test" << this;
    }
    Test& operator=(const Test& other)
    {
        qDebug() << "assgin operator" << this;
    }
    ~Test()
    {
        qDebug() << "destruct test" << this;
    }
};
   std::vector<Test> v;
   
   //测试1, push_back 放入 左值
   Test t;
   v.push_back(t);			//调用拷贝构造
   
   // 测试1, 结果:
   construct 0x3c296f940
   copy construct 0x15db0916660
   destruct test 0x3c296f940
   destruct  test 0x15db0916660

测试1结果:没有移动构造和移动赋值运算符的对象,push_back放入一个左值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数


	//测试2, push_back 放入右值,
    Test t;
    v.push_back(std::move(t));		//1.通过 move 将左值转换成 右值		//调用拷贝构造
  //  v.push_back(Test());			//2.构造临时对象为右值
    //1 和 2 的两种右值,其实是一样的;
    //第一种方式的 t对象,会在出了作用域之后析构
    //第二种生成一个临时对象,这一行结束之后,临时对象立即析构
    //在以下测试统一使用第一种方式生成右值
    
	//测试2,结果:
	construct 0xc8c64ffce0
	copy construct 0x1dd8d28af00
	destruct  test 0xc8c64ffce0
	destruct test 0x1dd8d28af00

测试2结果:没有移动构造和移动赋值运算符的对象,push_back放入一个右值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数


    //测试3, emplace_back 放入 左值
    Test t;
    v.emplace_back(t);		//调用拷贝构造

	//测试3,结果:
	construct 0xe60db8fd20
	copy construct 0x2b7a4a35ab0
	destruct test 0xe60db8fd20
	destruct test 0x2b7a4a35ab0

测试3结果:没有移动构造和移动赋值运算符的对象, emplace_back放入一个左值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数


	//测试4, emplace_back放入右值
    Test t;
    v.emplace_back(std::move(t));	//调用拷贝构造
	
	//测试4,结果:
	construct 0xf1004ff850
	copy construct 0x2a4b16a79a0
	destruct test 0xf1004ff850
	destruct  test 0x2a4b16a79a0

测试4结果:没有移动构造和移动赋值运算符的对象, emplace_back放入一个右值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数

2.有 移动构造函数移动赋值运算符
class Test
{
public:
    Test()
    {
        qDebug() << "construct" << this;
    }

    Test (const Test& other)
    {
        qDebug() << "copy construct" << this;
    }

    Test& operator=(const Test& other)
    {
        qDebug() << "assgin operator" << this;
    }

    Test (Test&& other)
    {
        qDebug() << "move construct" << this;
    }
    Test& operator=(Test&& other)
    {
        qDebug() << "move operator" << this;
    }
    ~Test()
    {
        qDebug() << "destruct test" << this;
    }
};

依次将上面的测试再进行一次:

	//测试5, push_back 放入左值
    Test t;
    v.push_back(t);		//调用拷贝构造

	//测试5,结果
	construct 0x73832ff720
	copy construct 0x1b70034d390
	destruct test 0x73832ff720
	destruct test 0x1b70034d390

测试5结果:移动构造和移动赋值运算符的对象, push_back放入一个左值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数


	//测试6, push_back放入右值
    Test t;
    v.push_back(std::move(t));		//调用移动构造

	//测试6,结果:
	construct 0x7dd78ff770
	move construct 0x243f1bc3f40
	destruct test 0x7dd78ff770
	destruct test 0x243f1bc3f40

测试6结果:移动构造和移动赋值运算符的对象,push_back放入一个右值,是调用一次构造函数生成对象t,一次移动构造函数,两次析构函数


	//测试7, emplace_back放入左值
    Test t;
    v.emplace_back(t);		//调用拷贝构造

	//测试7,结果:
	construct 0xbc301bf7c0
	copy construct 0x27f1caee380
	destruct  test 0xbc301bf7c0
	destruct  test 0x27f1caee380

测试7结果:移动构造和移动赋值运算符的对象,emplace_back放入一个左值,是调用一次构造函数生成对象t,一次拷贝构造函数,两次析构函数


	//测试8, emplace_back放入右值
    Test t;
    v.emplace_back(std::move(t));		//调用移动构造

	//测试8,结果:
	construct 0x95bbb8f930
	move construct 0x246db820f20
	destruct test 0x95bbb8f930
	destruct  test 0x246db820f20

测试8结果:移动构造和移动赋值运算符的对象,emplace_back放入一个右值,是调用一次构造函数生成对象t,一次移动构造函数,两次析构函数

结论:

1.没有移动构造和移动赋值运算符

左值右值
push_back拷贝构造函数拷贝构造函数
emplace_back拷贝构造函数拷贝构造函数

2.有移动构造和移动赋值运算符

左值右值
push_back拷贝构造函数移动构造函数
emplace_back拷贝构造函数移动构造函数
  • 看起来,无论是有移动构造和移动赋值运算符的对象,还是没有这两个函数的对象,emplace_backpush_back表现出来的特征是相同的, 并未出现任何性能上的改善与提升

正确使用:

  • emplace_back(Args...);
  • 实际,emplace_back真正能带来效率上的提升的用法是:直接在emplace_back里面传递参数原地调用构造函数,构造出一个对象,这样做至少可以节省一次 拷贝构造(针对左值) 或者 移动构造(针对右值) 带来的开销;而不是预先生成一个左值或右值类型的对象,然后再将其放入到emplace_back的参数中,这样的做法与push_back并无差异;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值