c ++危险的铸造代码

时间:2012-12-10 22:46:54

标签: c++ inheritance polymorphism dynamic-cast static-cast

我很确定这是危险的代码。但是,我想查看是否有人知道 究竟会出错。

假设我有这个类结构:

class A {
protected:
  int a;
public:
  A() { a = 0; }        
  int getA() { return a; }
  void setA(int v) { a = v; }
};

class B: public A {
protected:
  int b;
public:
  B() { b = 0; }
};

然后假设我想要一种自动扩展类的方法:

class Base {
public:
   virtual ~Base() {}
};

template <typename T>
class Test: public T, public Base {};

我可以做出的一个真正重要保证是BaseTest都不会有任何其他成员变量或方法。它们本质上是空类。

(可能)危险的代码如下:

int main() {
  B *b = new B();

  // dangerous part?
  // forcing Test<B> to point to to an address of type B
  Test<B> *test = static_cast<Test<B> *>(b);

  //
  A *a = dynamic_cast<A *>(test);
  a->setA(10);
  std::cout << "result: " << a->getA() << std::endl;
}

做这样的事情的理由是我使用的是类似于Test的类,但为了使它能够正常工作,必须制作新的实例T(即Test),同时复制传递的实例。如果我可以将Test指向T的内存地址,那将是非常好的。

如果Base没有添加虚拟析构函数,并且由于Test没有添加任何内容,我认为这段代码实际上是可以的。但是,添加虚拟析构函数会让我担心类型信息可能会添加到类中。如果是这种情况,则可能会导致内存访问冲突。

最后,我可以说这个代码在我的计算机/编译器(clang)上工作正常,但这当然不能保证它不会对内存做坏事和/或不会在另一个编译器/机器上完全失败。

3 个答案:

答案 0 :(得分:5)

删除指针时将调用虚析构函数Base::~Base。由于B没有正确的vtable(在此处发布的代码中根本没有),因此不会很好地结束。

它只适用于这种情况,因为你有内存泄漏,你永远不会删除test

答案 1 :(得分:1)

您的代码会产生未定义的行为,因为它违反了严格的别名。即使它没有,你也在调用UB,因为B和A都不是多态类,并且指向的对象不是多态类,因此dynamic_cast不能成功。您正在尝试访问不存在的Base对象,以便在使用dynamic_cast时确定运行时类型。

  

我能做出的一个非常重要的保证是既不是基地   也不会有任何其他成员变量或方法。他们是   基本上是空的。

它根本不重要 - 它完全无关紧要。该标准必须要求EBO才能开始重要,但事实并非如此。

答案 2 :(得分:-1)

只要您不对Test<B>*执行任何操作并避免使用智能指针或自动内存管理等任何魔法,您应该没问题。

您应该确保查找隐藏的代码,例如调试打印或将检查对象的日志记录。我试图查看像这样设置的指针的值,让调试器崩溃了。我敢打赌这会给你带来一些痛苦,但你应该能够让它发挥作用。

我认为真正的问题是维护。在某个开发人员对Test<B>*执行操作之前需要多长时间?