给定一个不完整的类型:
struct S;
那么以下声明是:
S *p; // ok, pointer to incomplete types is allowed
std::deque<S> l; // error, instantiating std::deque with incomplete type is UB
但是下面的声明呢?
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
编辑:这个问题使用了std::list
而不是std::deque
,但是这违背了这个问题的目的,因为std::list
被明确允许使用std::deque
似乎没有这样的权限。
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?
这实际上是这里有趣的一点。是的,不允许用不完整的类型实例化该容器,没有对其进行规定。但问题是它是否真的被实例化了。根据核心语言,它不一定是。
[临时安装]
1除非类模板专门化已经显式实例化或显式专门化,否则当专门化在需要完全定义的对象类型的上下文中被引用时,或者当类类型的完整性影响程序的语义学时,类模板专门化是隐式实例化的...
指向类型的指针不需要类型是完整的。因此,仅此声明通常不足以导致类模板的实例化,因此确定容器的需求在此被违反可能为时过早。
当然,除非我们采取“类类型的完整性影响程序的语义学”将合同违规包括在标准库中。我想,这里可以实例化一个实现。我不知道任何实现,但是,所以这可能不是欲望的解释。
因此,为了谨慎起见,我也认为这是错误的。
std::deque<S*> p; // not really sure about this one
这很好。无论S
是否完整,S*
仍然是一个完整的对象类型。我这样说是因为它不包括在
[基本类型]
5已声明但未定义的类,某些上下文中的枚举类型([dcl.enum]),或未知绑定或不完整元素类型的数组,是未完全定义的对象类型。不完全定义的对象类型和cv无效是不完全类型([basic.fundamental])。对象不应定义为具有不完整类型。
有关S
完整性的约束仅在尝试在执行解引用或指针算术的表达式中使用此类指针时出现。但是指针类型本身仍然是完整的。因此,它是容器类型的有效模板参数。