【问题标题】:Why do STL containers use copying to populate in resize?为什么 STL 容器使用复制来填充调整大小?
【发布时间】:2010-08-19 01:08:12
【问题描述】:

所有实现 resize 的 STL 容器都使用副本来填充新元素,即使副本的源是默认构造对象?

为什么会这样?

我认为没有优势和一些成本。


作为上下文,我在寻找 a random access container for elements that can't be copied 时遇到了这个问题:

【问题讨论】:

  • 有什么选择?容器是否记得哪个元素是默认构造的,哪个元素被覆盖/复制到?这有点傻。你还有什么想法吗?
  • @Nikolai:为什么需要这样做?如果 resize 默认构造一个元素然后复制它 50 次(而不像现在这样跟踪它的来源)是可以的,为什么它会默认构造它 50 次不呢?
  • 哦,我看错了这个问题。我可以想象原因是默认构造可能涉及分配,并且复制构造可能通过浅拷贝/引用计数/COW 来完成,就像 GNU std::string 实现一样。
  • 这个问题是模棱两可的 - 因此尼古拉最初的困惑。请考虑从“新空间”更改为“用于附加元素的新空间”之类的内容,或者明确表明您不是在谈论将现有元素移入的“新空间”。您可以添加一个示例: size()==10;调整大小(20)->(如果重新分配 [0..9]'=[0..9]); [10]'=X(); [11]'=[10]...[19]'=[10] 与 ...[10]'=X()...[19]'=X(); Nikolai 的评论是我能想到的唯一理由,而且还不错。

标签: c++ stl design-choices


【解决方案1】:

它节省了复杂性。我们当然需要复制构造的情况,而默认构造可以建模为复制默认构造的对象。

性能损失可以忽略不计。写入零的速度与复制零的速度大致相同。兼容性损失为零,因为无论如何所有容器都需要可复制性。另一方面,默认构造不是必需的。

如果您真的想使用带有不可复制对象的标准容器,请查看 C++0x 并使用 emplace 就地构造。但是,没有办法同时emplace 多个元素。 (如果您使用的是deque,那么emplace 循环与resize 相比应该不会有太大的性能损失。)

【讨论】:

  • 即使使用vector,您也始终可以提前使用reserve 来抵消性能影响。
  • @Matthieu:是的。不过,vector::reserve 可能会导致 move/copy。
  • 确实如此,以防容量不足。
【解决方案2】:

在您的情况下,也许您最好将 指针 存储到容器中的那些对象 -- 可以复制指针。

关于在容器中复制;有什么选择?如果您必须重新分配一个新的内存块来存储正在存储的内容,那么您必须以某种方式获取现有数据!

【讨论】:

  • 后者仅在您需要保持连续性时才需要。还有其他选择。
  • 无类型分配、placement new 和默认构造函数甚至可以用于超大块分配。
【解决方案3】:

我能想到这种行为的唯一原因是容器支持插入并且插入需要副本。您应该能够以类似于默认构造新元素的deque(分页且非连续)的方式创建支持调整大小的容器。但是,您必须禁止分配整个容器以及插入元素 - 您可以修改集合中构造的对象。

我的猜测是,没有人认为需要一个不支持插入且不实现值类型复制的集合。另外一点,您可能应该在它关闭之前将其标记为 wiki ;)

【讨论】:

  • 他们这样做的方式使界面任意且不必要地更宽。 OTOH 某些类型的集合可能无法绕过它,使其统一具有它的优势。
【解决方案4】:

标准容器定义了对值类型的 CopyConstructible 和 Assignable 要求,这些要求足以支持对容器和序列的所有操作(您可能还希望它们对于关联容器具有可比性,但即使这样也不是必需的因为你可以提供一个比较器)。

您所要求的是,对一组操作有一组要求,这些操作由 Container 的一部分加上 Sequence 中的某些内容组成(即那些永远不会重新定位其内容的容器上的 1 参数 resize(),@ 987654322@、clear() 和不包括*it = t 的迭代器接口),以及其余的另一组要求。标准库更喜欢以相反的方式执行此操作:选择一组涵盖几乎所有内容的通用要求,然后对少量功能有附加要求(例如要求默认可构造以便调用 resize() 而无需指定第二个参数)。

在构思容器时并没有考虑到您的特定操作集 - 复制和分配是其设计目的所固有的,即包含放入其中的值,因此我推测在 Stepanov 的想法中这不是“一小部分功能”。因此存在更广泛的要求,因为抽象 Container 比您建议的 ResizeableCollectionOfDefaultConstructedObjects 大。事实上,去掉 resize() 和 CollectionOfDefaultConstructedObjects 几乎只是一个数组。我猜 STL 和 C++ 标准的设计者并没有经常遇到您的用例,以至于认为它值得抽象。

【讨论】:

    猜你喜欢
    • 2018-04-20
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 2012-01-28
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多