这种未定义的行为?

时间:2013-07-09 17:47:48

标签: c++ undefined-behavior

我在代码库中找到了以下代码。我的同事认为这没关系,但看起来像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]) );
   }

}

2 个答案:

答案 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