为了观察std::vector中push_back和emplace_back的区别,我写了以上程序。根据输出发现,Base(1)被构造了3次,其中复制构造函数调了2次,Base(2)被构造了1次,没调用复制构造函数。那么Base(1)的复制构造函数被调了2次呢?
那么还有一次复制构造函数来自哪里?注意到 std::vector 为了支持任意大小,在增加元素的时候会出现扩容操作,而扩容的方法是重新分配空间,然后把数据复制过去,因此会在复制的过程中调用复制构造函数。
在这段程序中,可以发现当 i>0 时,当 i 达到 2^n (n=01234) 的时候,调用完 Base(i) 构造函数之后,就会对所有小于i的对象逐个执行复制构造函数,然后逐个执行析构函数。这同时可以看出,libstdc++对vector的扩容方式是在放不下数据的时候,对空间进行倍增。
总结一下,如果不想对存在 vector 里面的对象调用太多复制构造函数,就不要经常增大 vector 的容量,否则 vector 容量倍增的时候会对其中的所有对象调复制构造函数。可以先用 std::vector<>::reserve() 预留空间,再做 emplace_back 操作。其他解决方案包括在 vector 中存放指针,这样在容量倍增的时候只复制指针而不是对象本身。