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

发布于 2024-07-15 22:22:44 字数 536 浏览 2 评论 0原文

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

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

似乎可以使用构造和销毁习语,因为它们已经在 std::vector 中完成,尽管对列表类进行了更多的簿记。

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

Why is that the single parameter constructor of std::list<T> requires T to be a default-constructible type? I mean the following code does not compile.

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

It seems possible to use the construct and destroy idioms as they have already done in the std::vector, albeit with more book-keeping the list class.

On a related note, why not have the capacity function in list? You can argue that such a function would pay memory allocation cost up-front and eliminate the overhead later on as you push_back objects. At least it will make the interfaces of two STL sequence containers slightly more consistent.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

云雾 2024-07-22 22:22:44

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

从你的要求来看,我认为你实际上想要保留()。 这对于向量来说是一次性的,因为它(非常)需要这样的东西; 没有特别要求使所有函数在所有 STL 容器中保持一致,尤其是当它们对其他容器没有什么意义时。

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

std::list doesn't have a capacity function because it makes no sense; it never has to resize like a vector does. It's capacity is only limited by the available memory, which is not easily determined.

From what you asked for, I think you actually want reserve(). That's a one-off for vector because it (badly) needs such a thing; there's no particular requirement to make all functions consistent across all STL containers, especially when they make little sense for others.

You can accomplish the same effect using a custom allocator. As Manuel suggested, look at boost.

明媚殇 2024-07-22 22:22:44

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

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

#include <vector>

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

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

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

There is no general requirement that the type be default constructible - it must be copyable and assignable. Your code does not work because you try to create a list of 10 items - they have to be constructed somehow and so the default constructor must be used - but only in this specific case. If you created an empty list and added to it, there would be no such requirement.

The same is true for other containers - try compiling the following:

#include <vector>

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

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

Regarding the second part of your question, I'd just observe that consistency of interface was not a prime design criterion for the standard containers - there is no intention, for example, that one type of container is a "drop-in" replacement for another. There is a good discussion of this in items 1 and 2 of Scott Meyers' book "Effective STL".

巷雨优美回忆 2024-07-22 22:22:44

尼尔已经回答了主要问题

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

您可以通过使用指向对象的指针的 STL 列表来规避此问题,但我想这对您来说已经是显而易见的了。

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

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

Neil already answered the main question.

Also note that you need a default constructor when calling resize().

You can circumvent this by having a STL list of pointers to objects but I guess this already was obvious to you.

On a related note, why not have the
capacity function in list? You can
argue that such a function would pay
memory allocation cost up-front and
eliminate the overhead later on as you
push_back objects. At least it will
make the interfaces of two STL
sequence containers slightly more
consistent.

I guess the problem here is that STL lists allow cross-list splicing. If you want to allocate memory upfront, have a look at the Boost Pool Allocator.

扛起拖把扫天下 2024-07-22 22:22:44

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

请参阅列表的 sgi stl 文档

The reason is that, when you construct a list of n elements (where n is the parameter you used in the constructor), the list fills its structure of n elements with copies of T().

See sgi stl documentation for list.

落墨 2024-07-22 22:22:44

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

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

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

So your question is really "why not have reserve and capacity functions in list?"

The answer to that is that there's no reason to reserve memory in advance for list - adding new elements never requires a realloc & copy for existing elements, there's no requirement that the memory holding the contents of a list be contiguous, and iterators don't get invalidated when doing a list::push_back().

All of those are the reason for the existence of vector<>::reserve(), and having memory in reserve for new elements is why a vector<> will perform placement new into raw memory.

呆萌少年 2024-07-22 22:22:44

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

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

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

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

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

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

Why is that the single parameter
constructor of std::list requires T
to be a default-constructible type?

Because this contructor - creates list with elements (number which you pass as parameter). Value of each element will be default. Also you could use constructor with two parameters, for create list with elements which will be initialized with second element value.

On a related note, why not have the
capacity function in list?

It doesn't have sense, because cost of adding new elements to list is much little than in case with vector.

std::vector does not have such a
restriction. My question is why not
use the same techniques
(create/destroy idioms) in the
std::list as well?

It is not restriction. Because if you don't use such constructor, default initializer will not required. Same thing true for vector.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文