0

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

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

似乎可以像在 std::vector 中所做的那样使用构造和销毁习语,尽管需要更多地记录列表类。

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

4

6 回答 6

5

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

根据您的要求,我认为您实际上想要reserve()。这对于矢量来说是一次性的,因为它(非常)需要这样的东西;没有特别要求使所有 STL 容器的所有功能保持一致,尤其是当它们对其他人毫无意义时。

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

于 2009-03-29T21:26:10.030 回答
4

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

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

#include <vector>

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

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

关于您问题的第二部分,我只是观察到接口的一致性不是标准容器的主要设计标准-例如,无意将一种类型的容器替换为其他。Scott Meyers 的“Effective STL”一书的第 1 项和第 2 项对此进行了很好的讨论。

于 2009-03-29T21:04:01.240 回答
3

尼尔已经回答了主要问题

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

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

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

我想这里的问题是STL 列表允许跨列表拼接。如果您想预先分配内存,请查看Boost Pool Allocator

于 2009-03-29T21:14:41.120 回答
2

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

有关列表,请参见sgi stl 文档

于 2009-03-29T21:14:06.253 回答
1

所以你的问题真的是“为什么列表中没有储备和容量功能?”

答案是没有理由提前为列表保留内存——添加新元素永远不需要对现有元素进行重新分配和复制,不需要保存列表内容的内存是连续的,迭代器不需要在执行list::push_back().

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

于 2009-03-29T21:58:29.393 回答
0

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

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

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

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

std::vector 没有这样的限制。我的问题是为什么不在 std::list 中也使用相同的技术(创建/销毁习语)?

这不是限制。因为如果您不使用此类构造函数,则不需要默认初始化程序。向量也是如此。

于 2009-03-29T21:07:53.430 回答