C++中的容器协方差

Dan*_*ger 18 c++ covariance

我知道C++不支持容器元素的协方差,就像在Java或C#中一样.所以下面的代码可能是未定义的行为:

#include <vector>
struct A {};
struct B : A {};
std::vector<B*> test;
std::vector<A*>* foo = reinterpret_cast<std::vector<A*>*>(&test);
Run Code Online (Sandbox Code Playgroud)

毫不奇怪,我在建议这个解决另一个问题时收到了downvotes .

但是C++标准的哪一部分确切地告诉我这将导致未定义的行为?它的保证,无论std::vector<A*>std::vector<B*>他们的指针存储在内存中的continguous块.它也保证了sizeof(A*) == sizeof(B*).最后,A* a = new B完全合法.

那么我标准的标准是什么坏的(风格除外)?

Jam*_*lis 16

这里违反的规则记录在C++ 03 3.10/15 [basic.lval]中,它指定了非正式地称为"严格别名规则"的内容.

如果程序试图通过不同于以下类型之一的左值访问对象的存储值,则行为未定义:

  • 对象的动态类型,

  • 一个cv限定版本的动态类型的对象,

  • 与对象的动态类型对应的有符号或无符号类型的类型,

  • 一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,

  • 一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),

  • 一个类型,它是对象动态类型的(可能是cv限定的)基类类型,

  • char或unsigned char类型.

简而言之,给定一个对象,您只能通过具有列表中某种类型的表达式来访问该对象.对于没有基类的类类型对象std::vector<T>,基本上只限于第一个,第二个和最后一个项目符号中指定的类型.

std::vector<Base*>并且std::vector<Derived*>是完全不相关的类型,你不能使用类型的对象,std::vector<Base*>就好像它是一个std::vector<Derived*>.如果您违反此规则,编译器可以执行各种操作,包括:

  • 对其中一个执行不同的优化,或者执行不同的优化

  • 以不同的方式列出一个内部成员,或

  • 假设a std::vector<Base*>*永远不能引用同一个对象,执行优化std::vector<Derived*>*

  • 使用运行时检查以确保您没有违反严格别名规则

[它也可能不做这些事情并且它可能"有效",但不能保证它会"正常工作",如果你改变编译器或编译器版本或编译设置,它可能都会停止"工作".我在这里使用吓唬报价是有原因的.:-)]

即使你只是一个Base*[N]你不能使用该数组就好像它是一个Derived*[N](虽然在这种情况下,使用可能会更安全,"更安全"意味着"仍然未定义,但不太可能让你陷入困境").