c++ - C++ 中的容器协方差

标签 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);

毫不奇怪,我在建议 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/

相关文章:

python - 如何从 3d numpy 数组中提取向量?

c++ - 使 std::unique<T> 与 std::unique<const T, CustomDeleterType> 兼容

c++ - 为什么图像没有出现在 mfc CListView/CListCtrl 的子项上?

c++ - 如何从 opencv 中的图像访问第一个 5*5 block ?

matlab - 多个数据集上的 PCA(主成分分析)

c# - 泛型协变和显式转换

c# - IEnumerable<T> 是如何反变的?

c++ - 重载 += 运算符作为友元函数

c++ - 如何在 C++ 中使用可以具有多种数据类型的单个变量

c# - N 替代和协方差支持?