noexcept移动构造函数对vector push_back的优化作用

先说结论:
1、vector push_back时,当置的元素个数超过其容量(capacity),那么vector会分配一个新的存储空间并且将原空间内容转移过去,若自定义的移动构造函数不是noexcept的,那么由于push_back需要保证强异常安全性,那么C++11及以上就会采用拷贝复制的方式,而若移动构造函数是noexcept的,那么C++11会开启优化,将原空间内容通过移动而非复制的方式转移到新空间,这样会大大提升速度。
2、push_back 一个右值引用后会通过移动构造直接将右值的内容移动到vecter对应存储空间中,这个操作与移动构造是否是noexcept的无关。
3、编译器自动生成的移动构造函数也是noexcept的。

下面实测
先定义一个类:

class A {
public:
  A (int x_arg) : x (x_arg) { 
      std::cout << "A (x_arg)\n"; 
      }
  A () { x = 0; std::cout << "A ()\n"; }

  A (const A &rhs)  { 
    x = rhs.x; 
    ss = rhs.ss;  
    std::cout << "A (A &)\n"; 
  }

  A (A &&rhs)  { 
      x = rhs.x; 
      ss = std::move(rhs.ss);  
      std::cout << "A (A &&)\n"; 
    }
    // 自定义了析构   不会自己生成默认移动构造  
  ~A() { 
      std::cout << "~A ()\n"; 
    }

private:
  int x;
  string ss = string(100, 'a');
};

A的移动构造是没有noexcept的,那么接着给一个A的vector push_back一个右值引用,看看会发生什么…

void test_emplace_back_4()
{
	std::vector<A> a;
    A obj(1);
    a.push_back(std::move(obj));
}

输出结果如下:

A (x_arg)
A (A &&)
~A ()
~A ()

可见结论2,push_back 一个右值引用后会通过移动构造直接将右值的内容移动到vecter对应存储空间中,并且这个操作与移动构造是否是noexcept的无关

接着验证结论1,测试push_back 300000个元素的耗时:

void test_emplace_back_4()
{
    std::vector<A> a;
    std::cout << "call push_back4:\n";
    auto start = system_clock::now();
    for (int i = 0; i < 300000; i++)
    {
        A obj(1);
        a.push_back(std::move(obj));   // 触发移动构造
        // copy constructor to vector
    }
        auto end = system_clock::now();
        auto duration = duration_cast<milliseconds>(end - start);
        cout << "time duration ms: " << duration.count() << endl; 
}

当移动构造是 noexcept 的时候,耗时约为65ms。
当移动构造是非 noexcept 的时候,耗时约为105ms。
提升显而易见。

接下来将自定义的析构函数、移动构造、拷贝构造全部删除(析构、复制、移动都会影响系统自动生成移动操作),采用编译器自动生成的默认移动构造函数,耗时与自定义的noexcept移动构造一样,因此,编译器自动生成的默认移动构造函数也是noexcept的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值