标准库容器和不完整类型的规则是什么?

cig*_*ien 9 c++ c++-standard-library language-lawyer incomplete-type

给定一个不完整的类型:

struct S; 
Run Code Online (Sandbox Code Playgroud)

那么下面的声明是:

S *p;            // ok, pointer to incomplete types is allowed

std::deque<S> l;  // error, instantiating std::deque with incomplete type is UB
Run Code Online (Sandbox Code Playgroud)

但是下面的声明呢?

std::deque<S> *p;   // seems to be UB like the previous case, 
                   // but is it ok if p is not used till S is defined?

std::deque<S*> p;   // not really sure about this one
Run Code Online (Sandbox Code Playgroud)

编辑:使用的问题std::list代替std::deque,但这违背了问题的目的,因为std::list明确允许使用不完整的类型。std::deque似乎没有这样的权限

Sto*_*ica 8

std::deque<S> *p;   // seems to be UB like the previous case, 
                   // but is it ok if p is not used till S is defined?
Run Code Online (Sandbox Code Playgroud)

这实际上是这里有趣的一点。是的,不允许使用不完整的类型实例化该容器,没有规定。但问题变成了它是否真的被实例化了。根据核心语言,它不一定是。

[temp.inst]

1除非类模板特化已被显式实例化或显式特化,否则当在需要完全定义的对象类型的上下文中引用该特化时,或者当类类型的完整性影响到类模板的语义时,类模板特化将被隐式实例化程序。

指向类型的指针不要求类型是完整的。因此,仅凭此声明通常不足以导致类模板的实例化,因此确定此处违反了容器的要求可能还为时过早。

当然,除非我们采取“类类型的完整性影响程序的语义”在标准库中包含违反合同的内容。我想一个实现可以在这里实例化。然而,我不知道有任何实现,所以这可能不是欲望解释。

所以为了谨慎起见,我也认为这个 UB。


std::deque<S*> p;  // not really sure about this one
Run Code Online (Sandbox Code Playgroud)

这可以。无论是否S完整,S*仍然是一个完整的对象类型。我这样说是因为它不包括在

[基本类型]

5已声明但未定义的类,某些上下文中的枚举类型([dcl.enum]),或未知边界或不完整元素类型的数组,是未完全定义的对象类型。不完全定义的对象类型和 cv void 是不完全类型([basic.fundamental])。对象不应被定义为具有不完整的类型。

S仅当尝试在执行取消引用或指针算术的表达式中使用此类指针时,才会出现有关完整性的约束。但是指针类型本身还是完整的。所以它是容器类型的有效模板参数。