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似乎没有这样的权限。
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?
这实际上是这里有趣的一点。是的,不允许使用不完整的类型实例化该容器,没有规定。但问题变成了它是否真的被实例化了。根据核心语言,它不一定是。
[temp.inst]
1除非类模板特化已被显式实例化或显式特化,否则当在需要完全定义的对象类型的上下文中引用该特化时,或者当类类型的完整性影响到类模板的语义时,类模板特化将被隐式实例化程序。
指向类型的指针不要求类型是完整的。因此,仅凭此声明通常不足以导致类模板的实例化,因此确定此处违反了容器的要求可能还为时过早。
当然,除非我们采取“类类型的完整性影响程序的语义”在标准库中包含违反合同的内容。我想一个实现可以在这里实例化。然而,我不知道有任何实现,所以这可能不是欲望解释。
所以为了谨慎起见,我也认为这个 UB。
Run Code Online (Sandbox Code Playgroud)std::deque<S*> p; // not really sure about this one
这可以。无论是否S完整,S*仍然是一个完整的对象类型。我这样说是因为它不包括在
[基本类型]
5已声明但未定义的类,某些上下文中的枚举类型([dcl.enum]),或未知边界或不完整元素类型的数组,是未完全定义的对象类型。不完全定义的对象类型和 cv void 是不完全类型([basic.fundamental])。对象不应被定义为具有不完整的类型。
S仅当尝试在执行取消引用或指针算术的表达式中使用此类指针时,才会出现有关完整性的约束。但是指针类型本身还是完整的。所以它是容器类型的有效模板参数。