为什么只有这些C++标准库容器能够保证允许不完整类型?

7
众所周知,通常情况下,C++标准库容器无法与不完整类型一起实例化。这样做的结果是未定义行为,尽管在实践中,给定的实现将接受代码而没有问题,或者发出编译错误。有关此限制的讨论可以在这里找到:为什么C ++容器不允许不完整类型? 但是,在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的结果。该文件指出,“基于Issaquah会议上的讨论”,决定首先将此支持限制在这三个容器中。但是为什么呢?

3
这些容器只需要一个指向所存储对象类型的 指针。对于指向类型的指针,你不需要完整的定义。 - Some programmer dude
3
我很惊讶于 std::forward_liststd::list 允许这样做,因为它们的节点可以通过值存储对象。我猜想 在引用列表的任何成员之前,T 必须是完整的类型。"fixes" 这个问题。 - NathanOliver
@Someprogrammerdude 你对于 std::deque 有什么看法?我认为 deque 并不需要提前完整的类型,因为它本质上是 listvector 的混合体。 - user7860670
2个回答

1
因为我们知道如何实现这些容器来处理不完整的类型,而不会破坏ABI。
另一方面,std::array需要知道元素的大小(例如)。

1
Q. 向量(vector)难道不也需要知道对象的大小吗?默认分配器肯定是基于对象大小工作的。 - Mansoor
2
libc++可以为其他容器添加支持——但是我们必须改变这些容器的ABI。我们并不想这样做。 - Marshall Clow
1
@Mansoor 这就是 T 须在引用 list 的任何成员之前完成特化的地方。这时候就需要使用语言了。仅仅实例化类时,您不需要知道 T。但是,在实际使用类时,标准要求在使用之前必须将其完整定义。 - NathanOliver
@NathanOliver 的那个 "T 应该在……之前完成" 打开了许多用途,不仅限于容器。并且将 "不完整类型" 错误减少到了意味着 "你没有提供足够的代码"。 - Ripi2
N3890表示,libc++的deque会发生ABI破坏,但并未对unordered_map等其他内容提出类似的声明。 - Brian Bi
显示剩余3条评论

1

为什么?

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

Matt Austern在他的文章《The Standard Librarian: Containers of Incomplete Types》中记录了这一点,但该文章已不再可用,但还在Boost Containers of Incomplete Types中引用。

C++17的这一变化通过撤销这个全面禁令来纠正造成的伤害。


1
C++17所做的允许在某种程度上是有追溯性的,我不知道有哪个实现不允许由于语法而存在不完整类型。相当多的人依赖它或boost的variant。 - Swift - Friday Pie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接