【问题标题】:Why are there no capacity argument in the constructors for the containers?为什么容器的构造函数中没有容量参数?
【发布时间】:2011-08-13 02:53:46
【问题描述】:

如果我想将容量设置为std::vector,我必须调用.reserve(...),是否有任何理由在stl、std::stringstd::vector 中的容器的构造函数中没有容量参数?

【问题讨论】:

  • vector 确实有一个构造函数,它需要一个大小

标签: c++ stl containers


【解决方案1】:

有一个明显的原因:这样的构造函数会是什么样子?

所有的序列容器都已经有一个构造函数,可以用一个整数参数调用。该构造函数将容器的大小调整为具有指定数量的元素。

是的,您可以添加第二个参数(如 bool reserve_instead_of_resize),以便能够将此构造函数用于初始调整大小和初始保留,但我认为最终结果会令人困惑。

【讨论】:

  • 它可以采用另一个不同的整数参数作为保留大小 - 除非在 T = size_t 的情况下与初始值的不同 const T & 参数冲突(并且可能与它混淆在其他情况下,其中一个可以转换为另一个)。
  • 是的。还有一致性的问题:reserve 只对向量有意义,所以我们最终会得到另一个只针对向量的构造函数。我认为所有(或大多数)其他构造函数都可用于所有序列容器(尽管 string 确实有一些额外的构造函数,但它也不是一个通用的容器)。对于它的价值,我很少使用储备;它有时作为一种优化很有用,但我认为不够频繁,不能保证另一个构造函数。
  • 我非常偶尔使用reserve 不是作为优化,而是为了防止重新分配的语义影响——迭代器和指针失效以及出现异常的可能性。我同意它不值得一个构造函数,或者更确切地说是现有构造函数的一整套副本。在最坏的情况下,我认为你想用非平凡的内容构建并保留,你害怕重新分配的成本。所以需要先构造空,然后保留,再插入内容。
  • 参数使用什么的问题可以用一个包含整数的包装类std::reserve来回答。我仍然不得不同意这不值得。
  • 构造函数中的额外枚举,例如矢量(大小_t n,AllocType e = eResize)。我将非常感激这一点,因为使用单独的储备调用并未在美学上进行优化。
【解决方案2】:

您可以简单地创建一个用于创建保留向量的函数:

// make_reserved_vector
template <typename... T>
std::vector<T...> make_reserved_vector(size_t n) {
    std::vector<T...> vec;
    vec.reserve(n);
    return vec;
}

并用作:

auto myvec = make_reserved_vector<int>(32768);

【讨论】:

  • 这是个好主意。这解决了这个问题,但是 C++ 库仍然存在一个先天问题:您可能需要为两次内存分配付费(第一个向量构造函数,当您不知道默认容量是多少时),然后是第二个(当您保留和可能的解除分配和重新分配)。您的解决方案充分利用了这一点,但我认为 C++ 委员会需要重新审视这个问题。
  • @rts1 :没错,这也是我关心的问题。可能有一个“默认大小储备”,然后是我们调用的另一个储备。它可能有多个构造函数,一个占用保留大小。
  • 相当老的 q/a,但在某个地方我必须释放我的挫败感 ;) 我不明白为什么在初始容量和初始大小之间进行选择时,他们会选择大小。如果我们可以选择初始容量,则可以在构建后更改大小而无需额外费用。就像现在一样,我要么必须要求一个大小可能我不需要的向量,要么可能需要支付两次才能获得我想要的容量。恕我直言,这违反了 C++ 的第一原则,不要为不需要的东西付费。无论如何,你的函数可能是处理它的最好方法
【解决方案3】:

要创建一个向量,并同时指定其容量,请创建一个具有所需容量的向量,将所需的元素复制到其中,然后从复制返回的迭代器中擦除。 如果构造函数很慢,只需编写另一个带有特殊参数的构造函数,只保留内存。

int main (int argc, char** argv) {
  std::vector<size_t> v (10, 0);
  size_t tmp [3] = {0, 1, 2};
  std::vector<size_t>::iterator i (v.begin ());
  i = std::copy ((const size_t*)tmp, (const size_t*) &tmp [3], v.begin ());
  v.erase (i, v.end ());
  std::cout << "\tv capacity == " << v.capacity () << std::endl;
}

将输出:

v 容量 == 10

【讨论】:

  • 如果元素的构造函数有副作用(或者只是很慢),那么这与创建一个空向量然后保留一些容量有不同的行为。
  • 如果构造器很慢,在你的类中创建一个只保留内存的 foo 构造器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 2014-06-18
  • 1970-01-01
  • 2019-12-18
  • 2010-12-29
  • 2011-10-09
  • 2014-08-22
相关资源
最近更新 更多