C ++标准列表和默认构造类型

时间:2009-03-29 21:02:24

标签: c++ list stl default-constructor

为什么std::list<T>的单个参数构造函数需要T为默认构造类型?我的意思是以下代码无法编译。

struct Foo { // does not have default constructor.
  Foo (int i) {} 
}
int main(void) {
  std::list<Foo> l(10);
}

似乎可以使用construct and destroy idioms,就像他们已经在std :: vector中完成的那样,尽管有更多的簿记列表类。

在相关的说明中,为什么列表中没有容量功能?您可以争辩说,这样的函数会预先支付内存分配成本,并在以后消除push_back对象的开销。至少它会使两个STL序列容器的接口稍微更加一致。

6 个答案:

答案 0 :(得分:5)

std :: list没有容量功能,因为没有意义;它永远不会像矢量那样调整大小。它的容量仅受可用内存的限制,这是不容易确定的。

根据你的要求,我认为你真的想要保留()。这是向量的一次性,因为它(非常)需要这样的东西;并没有特别要求在所有STL容器中使所有功能保持一致,特别是当它们对其他容器没有意义时。

您可以使用自定义分配器完成相同的效果。正如曼努埃尔建议的那样,看看提升。

答案 1 :(得分:4)

没有一般要求该类型是默认可构造的 - 它必须是可复制和可分配的。您的代码不起作用,因为您尝试创建一个包含10个项目的列表 - 它们必须以某种方式构造,因此必须使用默认构造函数 - 但仅限于此特定情况。如果您创建了一个空列表并添加到其中,则不会有这样的要求。

其他容器也是如此 - 尝试编译以下内容:

#include <vector>

struct A {
    A( int x ) : z(x) {}
    int z;
};

std::vector <A> a(10);

关于问题的第二部分,我只是观察到界面的一致性不是标准容器的主要设计标准 - 例如,没有意图一种类型的容器是“插入式” “替换另一个人。 Scott Meyers的书“Effective STL”中的第1和第2项对此进行了很好的讨论。

答案 2 :(得分:3)

Neil already answered the main question

另请注意,调用resize()时需要默认构造函数。

您可以通过提供指向对象的STL列表来规避这一点,但我想这已经很明显了。

  

在相关的说明中,为什么不拥有   列表中的容量功能?您可以   认为这样的功能会付出代价   内存分配成本预先和   以后消除开销   push_back对象。至少它会   制作两个STL的接口   序列容器略多   是一致的。

我想这里的问题是STL lists allow cross-list splicing。如果您想预先分配内存,请查看Boost Pool Allocator

答案 3 :(得分:2)

原因在于,当您构造n个元素的列表(其中n是您在构造函数中使用的参数)时,该列表使用T()的副本填充其n个元素的结构。

请参阅sgi stl documentation for list

答案 4 :(得分:0)

  

为什么是单个参数   std :: list的构造函数需要T.   是一个默认可构造类型?

因为这个构造函数 - 创建包含元素的列表(作为参数传递的数字)。每个元素的值都是默认值。您还可以使用带有两个参数的构造函数,对于包含元素的创建列表,这些元素将使用第二个元素值进行初始化。

  

在相关的说明中,为什么不拥有   列表中的容量功能?

没有意义,因为向列表添加新元素的成本比向量的情况要少得多。

  

std :: vector没有这样的   限制。我的问题是为什么不   使用相同的技术   (创造/破坏成语)   std :: list也是?

这不是限制。因为如果您不使用此类构造函数,则不需要默认初始值设定项。矢量也是如此。

答案 5 :(得分:0)

所以你的问题确实是“为什么列表中没有预留和容量功能?”

答案是没有理由提前为列表预留内存 - 添加新元素永远不需要realloc&amp;复制现有元素时,不要求保存列表内容的内存是连续的,并且在执行list::push_back()时迭代器不会失效。

所有这些都是vector<>::reserve()存在的原因,并且为新元素保留了内存是vector<>将原始内存放置new的原因。