在矢量中插入数据时多次调用复制构造函数

Copy constructor called many times when data is inserted in vector

本文关键字:调用 复制 构造函数 数据 插入      更新时间:2023-10-16
#include <iostream>
#include <vector>
using namespace std;
class base
{
    int x;
public:
    base(int k){x =k; }
    void display()
    {
        cout<<x<<endl;
    }
    base(const base&)
    {
        cout<<"base copy constructor:"<<endl;
    }
};
int main()
{
    vector<base> v;
    base obase[5]={4,14,19,24,29};
    for(int i=0; i<5; i++)
    {
        v.push_back(obase[i]);
    }
}

当数据插入到向量中时,使用复制构造函数将数据复制到该向量。

当我运行这个程序时,

  1. 对于第一次插入(i=0(,调用一次复制构造函数
  2. 对于第二次插入(i=1(,调用两次复制构造函数
  3. 对于第三次插入(i=3(,调用三次复制构造函数
  4. 对于第四次插入(i=3(,调用四次复制构造函数
  5. 对于第五次插入(i=4(,调用五次复制构造函数

请任何人告诉我为什么会发生这种事?对于每次插入,复制构造函数不应该只调用一次吗?

push_back()的调用会根据需要增加向量的大小,这涉及到复制向量的内容。由于您已经知道它将包含五个元素,要么是循环前的v.reserve(5);,要么使用范围构造函数:

base obase[5]={4,14,19,24,29};
vector<base> v(obase, obase+5);

您的复制构造函数有缺陷,您忘记了实际复制数据:(

base(const base& that) : x(that.x)
{
    cout << "base copy constructorn";
}

此外,如果你有一个现代编译器,你可以编写一个移动构造函数并学习一些新的东西:

base(base&& that) : x(that.x)
{
    cout << "base move constructorn";
}

如果v需要调整其内部缓冲区的大小,它通常会分配一个全新的内存区域,因此它需要将以前在向量中的所有对象复制到新位置。这是使用常规复制完成的,因此会调用复制构造函数。

如果您可以估计需要多少元素,那么您应该在向量上调用reserve()来提前预留存储。

请注意,std::vector的调整大小/增长行为取决于实现,因此您的代码示例将使用不同的标准库实现产生不同的结果。