【问题标题】:Why are only these C++ standard library containers guaranteed to allow incomplete types?为什么只有这些 C++ 标准库容器保证允许不完整的类型?
【发布时间】:2020-01-14 14:09:37
【问题描述】:

众所周知,C++ 标准库容器通常不能用不完整的类型进行实例化。这样做的结果是 UB,尽管实际上给定的实现要么毫无问题地接受代码,要么发出编译错误。关于这个限制的讨论可以在这里找到:Why C++ containers don't allow incomplete types?

但是,在 C++17 中,有三个容器明确允许不完整类型:std::forward_list (26.3.9.1/4)、std::list (26.3.10.1/4) 和 std::vector (26.3. 11.1/4)。

这是N4510 的结果。该文件指出,“基于对伊萨夸会议的讨论”,决定至少在开始时将此类支持限制在这三个集装箱上。但为什么呢?

【问题讨论】:

  • 那些容器只需要一个指向所存储对象类型的指针。对于指向类型的指针,您不需要完整的定义。
  • 我真的很惊讶std::forward_liststd::list 允许它,因为它们的节点可以按值存储对象。我想 T 应该在引用生成的列表专业化的任何成员之前完成。“修复”。
  • @Someprogrammerdude std::deque 怎么样?我认为deque 没有任何理由要求提前完成类型,因为它本质上是listvector 的混合体。

标签: c++ c++17


【解决方案1】:

因为我们知道如何在不破坏 ABI 的情况下实现这些容器来处理不完整的类型。

另一方面,std::array 需要知道一个元素有多大(例如)。

【讨论】:

  • 问。向量是否也不需要知道对象的大小?当然,默认分配器是根据对象大小工作的。
  • N3890 似乎表明除了std::array之外的所有容器都是可能的。
  • libc++ 可以添加对其他容器的支持 - 如果我们愿意更改这些容器的 ABI - 我们不会。
  • @NathanOliver(我相信我可以通过阅读源代码找到自己)如果你想递增到下一个元素,你怎么能在不知道大小的情况下这样做?
  • @Mansoor 这就是 T 应该在列表的任何成员被引用之前完成的地方。 语言开始发挥作用。要仅实例化该类,您无需知道T。要实际使用你所做的类,但标准要求它在使用前是完整的。
【解决方案2】:

但是为什么呢?

标准容器中不允许不完整类型的原因是某些容器可以使用它们,但有些则不能。他们当时并不想过多考虑这个问题,并全面禁止所有标准容器中的不完整类型。

Matt Austern 在他的精彩文章“标准图书馆员:不完整类型的容器”中记录了这一点,该文章不再可用,但在 Boost Containers of Incomplete Types 中仍有引用。

这项 C++17 更改通过消除该全面禁令所造成的伤害来实现正义。

【讨论】:

  • C++17 的允许是一种追溯方式,我不知道那些由于语法而不允许不完整类型的实现。相当多的人依赖它或 boosts 的变体。
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多