为什么 std::vector 适用于类定义中的不完整类型?

Why does std::vector work with incomplete types in class definitions?

本文关键字:类型 定义 vector std 适用于 为什么      更新时间:2023-10-16

出现了以下问题:

c++标准似乎说,std::vector需要一个完整的类型才能工作。(见 https://en.cppreference.com/w/cpp/container/vector)那么,为什么下面的代码仍然编译呢?

#include <vector>
struct parent;
struct child
{
std::vector<parent> parents; //parent is incomplete here!
};
struct parent
{
std::vector<child> children;
};

这似乎有悖常理。如果std::vector需要一个完整的类型,那么std::vector<parent>不应该编译,因为在child的类定义中只有它的前向声明是已知的。

  • 这种行为是类定义的特殊之处吗?
  • 我弄错了吗,std::vector不需要完整的类型?
  • 或者,这只是侥幸吗?从技术上讲,这是不允许的,但无论如何它适用于所有实现......

编辑

c++11 和 c++17 之间似乎有区别。我想了解 c++11 版本。

标准说(草案 N3690;这是 C++11 之后,C++14 之前):

[重新设置函数]

1 在某些情况下(替换函数、处理程序函数、 对用于实例化标准库模板的类型的操作 组件),C++标准库取决于 一个C++程序。如果这些组件不符合其要求,《标准》对实施没有要求

2 具体而言,在以下情况下,效果是不确定的:

— 如果在以下情况下使用不完整的类型 (3.9) 作为模板参数 实例化模板组件,除非特别允许 该组件。

鉴于标准没有要求,并且效果是未定义的(据我所知,这与未定义的行为相同),因此对实例化"不起作用"的期望与期望它(似乎)"工作"一样。


自 C++17 起,要求放宽了,如果与适当的分配器一起使用,则std::vector不需要完成值类型(默认分配器是合适的)。(这种自由并不延伸到使用所有成员函数;它们有额外的要求)。

标准报价(当前草案):

[矢量概述]

如果分配器满足分配器完整性要求,则在实例化向量时可以使用不完整类型 T。 在引用由此产生的载体特化的任何成员之前,T应是完整的。

[分配器.要求.完整性]

如果 X 是类型 T 的分配器类,则无论 T 是否为完整类型,X 都还满足分配器完整性要求:

  • X 是一个完整的类型,并且
  • 除value_type之外的所有成员类型的allocator_traits都是完整类型。

[默认分配器]

默认分配器的所有专用化都满足分配器完整性要求([分配器.要求.完整性])。