我在代码库中找到了以下代码。我的同事认为这没关系,但看起来像UB一样可疑。是不是UB?
class A {
//some stuff
};
class B : public A {
int a;
int b;
int c;
}
void foo( std::vector<A>& a ) {
std::vector<B> b;
for(size_t i = 0 ; i < a.size(); ++i ){
b.push_back( *(B*)(&a[i]) );
}
//remove some elements from b
for(size_t i = 0 ; i < b.size(); ++i ){
a.push_back( *(A*)(&b[i]) );
}
}
答案 0 :(得分:6)
这是未定义的行为。原始向量中的真实对象是A
,而不是B
,因此强制转换不正确,您将获得未定义的行为。
该代码最常见的结果是不正确的数据(B
中不存在的A
成员从向量中的下一个对象(如果存在)读取,或者从以下内存位置读取)或崩溃(如果碰巧是最后一个元素,原始向量中没有保留额外的空间,并且读取恰好扩展到受保护的内存页。
答案 1 :(得分:1)
简短回答 - 是的,这是未定义的行为。
删除向量可以更清楚:
void foo( A a ) {
B b;
b = *(B*)(&a);
a = *(A*)(&b);
}
上述版本在涉及的内存问题方面与您的版本相同。最后一个陈述 - 对a
的分配 - 实际上很好。这是一个多态的向上翻转,事实上你甚至不需要额外的所有演员。这很好:
a = *&b;
第一项任务 - b
- 未定义。您正在尝试非法的多态转发。这可能是无害的,并且所有额外的强制转换将迫使编译器接受它。但这绝对是未定义的行为。
一般情况下,如果你使用带有C ++类的C风格的演员表,你就会遇到麻烦。尝试这种类型的向下转换的正确方法是使用dynamic_cast:
b = *(dynamic_cast<B*>(&a));
然而,这会在运行时失败,因为&a
不是B*
,事实上,我的编译器发出警告,我正在做的事情是荒谬的:
warning: dynamic_cast of 'A a' to 'class B*' can never succeed