【问题标题】:Copy constructor called many times when data is inserted in vector向向量中插入数据时多次调用复制构造函数
【发布时间】:2011-06-09 17:03:41
【问题描述】:
#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),调用了五次复制构造函数

请谁能告诉我为什么会这样?每次插入,拷贝构造函数不应该只调用一次吗?

【问题讨论】:

    标签: c++


    【解决方案1】:

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

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

    【讨论】:

    • 如果不需要连续的内存布局,另一种解决方法是使用std::deque&lt;&gt; 而不是std::vector&lt;&gt;
    【解决方案2】:

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

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

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

    base(base&& that) : x(that.x)
    {
        cout << "base move constructor\n";
    }
    

    【讨论】:

    • 你是绝对正确的。请您也解释一下为什么复制构造函数中需要“ const ”。如果我不使用它会产生编译错误。
    • @Alok:因为对非常量的引用不绑定到右值。如果这听起来对您来说太技术化,请不要担心。实际上,所有复制构造函数都有 const,因为它们仅从源读取而不修改它。删除 const 是没有意义的。
    • 非常感谢,非常好的描述
    【解决方案3】:

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

    如果您可以估计需要多少元素,您应该在向量上调用 reserve() 以预先预留存储空间。

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

    【讨论】:

    • 请你也解释一下为什么在复制构造函数中我需要 const 关键字?如果我不使用它,它会产生编译错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多