C++ 为什么std::vector在类定义中使用不完整的类型?

C++ 为什么std::vector在类定义中使用不完整的类型?,c++,c++11,language-lawyer,std,stdvector,C++,C++11,Language Lawyer,Std,Stdvector,出现了以下问题: > C++标准似乎说,代码STD::vector < /COD>需要一个完整的类型来工作。(请参阅)那么,为什么下面的代码仍在编译 #include <vector> struct parent; struct child { std::vector<parent> parents; //parent is incomplete here! }; struct parent { std::vector<child> c

出现了以下问题:

<> > C++标准似乎说,<>代码STD::vector < /COD>需要一个完整的类型来工作。(请参阅)那么,为什么下面的代码仍在编译

#include <vector>

struct parent;

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

struct parent
{
    std::vector<child> children;
};
#包括
结构父级;
结构子对象
{
std::vector parents;//这里的parent不完整!
};
结构父级
{
性病媒儿童;
};
这似乎违反直觉。如果
std::vector
需要完整的类型,则不应编译
std::vector
,因为在
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是一个完整类型,并且
  • 除值类型外,分配器的所有成员类型都是完整类型
[默认分配程序]

默认分配器的所有专门化都满足分配器完整性要求([allocator.requirements.completency])


我认为问题存在于这样一个事实上,即父类型并不是一个不完整的类型,因为您显式地定义了它。@AdrienGivry是的,在定义
子类时它是不完整的
classC++11需要完成;C++17但是:“如果分配器满足分配器完整性要求,则可以用不完整的元素类型实例化此容器(但不是其成员)。”请参见在问题中添加标准版本/@AdrienGivry。您似乎可以在定义
父项
之前实例化
子项
,请参阅:真正的问题只是c++11如何定义
std::vector
要求完整类型的需求。可能只是不需要诊断,标准库实现者可以编写适用于不完整类型的实现。尽管这样使用它不便于携带。@FrançoisAndrieux第二段仍然相关。@jan.sende No;定义的实现意味着实现需要记录行为(但未指定如何记录此类定义)。没有任何要求。程序可能在同一个或不同的编译器上编译、不编译、行为正确、行为错误等@eerorika所以行为没有定义?(不是指未定义的行为…@jan.sende我不知道未定义的行为与未定义的“效果”是相同还是不同)。从C++程序员的角度来看,我会假设它们的意思完全一样。如果我正在实现一个标准库,我会假设我不能基于此进行疯狂的优化。@jan.sende此处未定义意味着无法保证代码能够编译;这与在运行时执行非法操作(如零除)不同,在这种情况下,代码必须编译并运行所有不涉及非法操作的执行。