1

我在我们的代码库中找到了以下代码。我的同事认为这没关系,但它似乎可疑地像 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]) );
   }

}
4

2 回答 2

6

那是未定义的行为。原始向量内的真实对象是 a A,而不是 a B,因此强制转换不正确,您将获得未定义的行为。

该代码最常见的结果可能是不正确的数据(如果存在,则从向量中的下一个对象或从以下内存位置读取B不存在的成员)或崩溃(如果它恰好是最后一个元素A,原始向量中没有保留额外的空间,并且读取恰好扩展到受保护的内存页面。

于 2013-07-09T17:56:15.827 回答
1

简短的回答 - 是的,这是未定义的行为。

删除向量使这一点更清楚:

void foo( A a ) {
  B b;
  b = *(B*)(&a);
  a = *(A*)(&b);
}

就所涉及的内存问题而言,上述版本与您的版本相同。最后一条语句 - 分配给a- 实际上很好。这是一个多态向上转换,事实上你甚至不需要所有额外的转换。这可以:

a = *&b;

第一个赋值 - to b- 是未定义的。您正在尝试非法的多态向下转换。这可能是无害的,所有额外的转换都会迫使编译器接受它。但这绝对是未定义的行为。

一般来说,如果你在 C++ 类中使用 C 风格的强制转换,你就有麻烦了。尝试这种向下转换的正确方法是使用 dynamic_cast:

b = *(dynamic_cast<B*>(&a));

但是,这将在运行时失败,因为&ais not a B*,事实上,我的编译器会发出警告说我正在做的事情很荒谬:

warning: dynamic_cast of 'A a' to 'class B*' can never succeed
于 2013-07-09T19:20:25.160 回答