【问题标题】:std::vector and copy constructorsstd::vector 和复制构造函数
【发布时间】:2012-11-03 23:05:26
【问题描述】:
vector<X> v;
X x;
v.push_back(x); v.push_back(x); v.push_back(x);

为什么这段代码调用类X的复制构造函数6次? (使用 g++ 4.7.2 STL)

拜托,我想准确地了解这个特殊的 STL 的底层会发生什么。

【问题讨论】:

  • 可能是因为一些重定位(向量的所有元素必须在一个连续的内存块中)
  • @KirilKirov 是的,这绝对是正确的,但我想确切地知道引擎盖下发生了什么。
  • 它是实现定义的。据我所知,该标准对此没有任何说明。
  • 尝试调用v.reserve(3),应该会减少复制构造函数的调用次数。

标签: c++ gcc stl


【解决方案1】:

当您插入xpush_back() 时,最终会重新分配内存以为新元素腾出空间。然后必须使用复制构造函数 X(const X&amp;) 复制已插入的成员。

如果你插入

v.reserve(3);

至少在前三个push_back()s 中阻止了重新分配,因此只有三个对X(const X&amp;) 的调用

【讨论】:

  • 总的来说,没错,但我提供了更准确的答案。
【解决方案2】:

您可以事先使用向量保留在向量中创建空间,以加快向向量添加元素的速度并阻止这种情况发生。

【讨论】:

  • resize 实际上会创建新对象,因此在 3 个新对象上调用默认构造函数。 push_back 将在列表末尾添加新创建的对象,他的向量中将有 6 个项目。储备是他在这里需要的。
【解决方案3】:

正确的答案是std::vector 是使用加倍数组实现的(参见:http://en.wikipedia.org/wiki/Dynamic_array),它调用了大约 2 * N 倍的复制构造函数。

例如,对于N = 100,000,它会调用复制构造函数231,071 次。正如已经指出的那样,可以通过调用v.reserve() 来减少重新分配的次数。

【讨论】:

  • “正确答案”是您的编译器对 std::vector 的实现 是使用加倍数组实现的。标准不需要这样的东西。
  • @Angew 我只考虑 gcc 的实现。查看问题。
  • 如果向量的大小每次变得太小时都会翻倍,那么您会产生大约 log(N) 次对复制构造函数的调用,而不是 2*N
【解决方案4】:

会发生这样的事情:

在第一次 push_back 之前,向量的容量(适合它分配的空间的元素数)为 0。所以当您执行第一次 push_back 时,它为 1 个项目分配空间并调用复制构造函数 (第一次调用)。

所以现在容量是一个,你告诉它添加另一个项目。所以它必须分配更多的空间,在这种情况下,空间用于多一个项目并将原始项目复制到新空间(第二次调用)。第二个 push_back 再次调用复制构造函数(第三次调用)。

现在您的容量为 2,并告诉它添加另一个项目。所以它必须分配更多空间并将项目复制到新空间(第 4 次和第 5 次调用)。然后第三个 push_back 再次调用复制构造函数(第 6 次调用)。

正如其他人指出的那样,您可以使用reserve,它将预先分配空间,避免重新分配的需要,从而避免调用复制构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-08
    • 2018-03-12
    • 2020-08-06
    • 2020-10-05
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多