标准库容器和不完整类型的规则是什么?
What are the rules for standard library containers and incomplete types?
给定一个不完整的类型:
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
明确地是 allowed to use incomplete types. std::deque
doesn't appear to have such permission.
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 Unless a class template specialization has been explicitly
instantiated or explicitly specialized, the class template
specialization is implicitly instantiated when the specialization is
referenced in a context that requires a completely-defined object type
or when the completeness of the class type affects the semantics of
the program.
指向类型的指针不要求类型是完整的。因此,仅此声明通常不足以导致 class 模板的实例化,因此确定此处违反了容器的要求可能还为时过早。
当然,除非我们采取 “class 类型的完整性会影响程序的语义” 以将违反契约的行为包含在标准库中。我想,一个实现 可以 在这里实例化。然而,我不知道有任何实现,所以这可能不是期望的解释。
所以为了谨慎起见,我也认为这个 UB。
std::deque<S*> p; // not really sure about this one
这很好。不管 S
是否完整,S*
仍然是一个完整的对象类型。我这样说是因为它不包含在
[basic.types]
5 A class that has been declared but not defined, an enumeration
type in certain contexts ([dcl.enum]), or an array of unknown bound or
of incomplete element type, is an incompletely-defined object type.
Incompletely-defined object types and cv void are incomplete types
([basic.fundamental]). Objects shall not be defined to have an
incomplete type.
有关 S
完整性的约束仅在尝试在执行取消引用或指针算术的表达式中使用此类指针时出现。但是指针类型本身还是完整的。所以它是容器类型的有效模板参数。
给定一个不完整的类型:
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
明确地是 allowed to use incomplete types. std::deque
doesn't appear to have such permission.
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 Unless a class template specialization has been explicitly instantiated or explicitly specialized, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.
指向类型的指针不要求类型是完整的。因此,仅此声明通常不足以导致 class 模板的实例化,因此确定此处违反了容器的要求可能还为时过早。
当然,除非我们采取 “class 类型的完整性会影响程序的语义” 以将违反契约的行为包含在标准库中。我想,一个实现 可以 在这里实例化。然而,我不知道有任何实现,所以这可能不是期望的解释。
所以为了谨慎起见,我也认为这个 UB。
std::deque<S*> p; // not really sure about this one
这很好。不管 S
是否完整,S*
仍然是一个完整的对象类型。我这样说是因为它不包含在
[basic.types]
5 A class that has been declared but not defined, an enumeration type in certain contexts ([dcl.enum]), or an array of unknown bound or of incomplete element type, is an incompletely-defined object type. Incompletely-defined object types and cv void are incomplete types ([basic.fundamental]). Objects shall not be defined to have an incomplete type.
有关 S
完整性的约束仅在尝试在执行取消引用或指针算术的表达式中使用此类指针时出现。但是指针类型本身还是完整的。所以它是容器类型的有效模板参数。