我知道 C++ 不支持容器元素的协方差,就像在 Java 或 C# 中一样。所以下面的代码可能是未定义的行为:
#include <vector>
struct A {};
struct B : A {};
std::vector<B*> test;
std::vector<A*>* foo = reinterpret_cast<std::vector<A*>*>(&test);
毫不奇怪,我在建议 another question 的解决方案时收到了反对票。 .
但是 C++ 标准的哪一部分确切地告诉我这将导致未定义的行为?保证std::vector<A*>
和 std::vector<B*>
将它们的指针存储在连续的内存块中。还保证sizeof(A*) == sizeof(B*)
.最后,A* a = new B
完全合法。
那么,我想到了标准中的哪些不良情绪(风格除外)?
最佳答案
此处违反的规则记录在 C++03 3.10/15 [basic.lval] 中,它指定了非正式地称为“严格别名规则”的内容
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
the dynamic type of the object,
a cv-qualified version of the dynamic type of the object,
a type that is the signed or unsigned type corresponding to the dynamic type of the object,
a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union),
a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
a char or unsigned char type.
简而言之,给定一个对象,您只能通过具有列表中一种类型的表达式访问该对象。对于没有基类的类类型对象,如 std::vector<T>
,基本上你只限于第一个、第二个和最后一个项目符号中命名的类型。
std::vector<Base*>
和 std::vector<Derived*>
是完全不相关的类型,您不能使用 std::vector<Base*>
类型的对象好像它是一个 std::vector<Derived*>
.如果您违反此规则,编译器可能会做各种事情,包括:
对一个与另一个执行不同的优化,或者
以不同的方式布置内部成员,或
假设
std::vector<Base*>*
执行优化永远不能与std::vector<Derived*>*
引用相同的对象使用运行时检查来确保您没有违反严格的别名规则
[它也可能不做这些事情并且它可能“工作”,但不能保证它会“工作”,如果你改变编译器或编译器版本或编译设置,它可能会停止“工作”。我在这里使用恐吓引号是有原因的。 :-)]
即使您刚刚拥有 Base*[N]
你不能像使用 Derived*[N]
一样使用该数组。 (虽然在这种情况下,使用可能会更安全,其中“更安全”的意思是“仍然未定义但不太可能让你陷入困境)。
关于c++ - C++ 中的容器协方差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4807643/