这颗钻石继承UB是MinGW中的一个错误吗?

时间:2013-05-31 22:28:23

标签: c++ windows mingw diamond-problem

#include <iostream>
#include <sstream>

class VeryBase {
protected:
    int a_;
public:
    VeryBase() : a_(1) {}
    virtual operator std::string() {
        return "0";
    }
};

class Base1 : public virtual VeryBase {
protected:
    int b_;
public:
    Base1() : b_(2) {}
    operator std::string() {
        return "1";
    }
};

class Base2 : public virtual VeryBase {
protected:
    int c_;
public:
    Base2() : c_(3) {}
    operator std::string() {
        return "2";
    }
};

class TargetClass : public Base1, public Base2 {
protected:
    int d_;
public:
    TargetClass() : d_(4) {}
    operator std::string() {
        std::ostringstream s;
        s << a_ << ' ' << b_ << ' ' <<  c_ << ' ' << d_ << std::endl;
        return s.str();
    }
};

int main()
{
    VeryBase* a = new TargetClass;
    Base1* b = dynamic_cast<Base1*>(a);
    Base2* c = dynamic_cast<Base2*>(a);

    std::cout << std::string(*a) //1 2 3 4
              << std::string(*b) //1 2 3 4
              << std::string(*c) //? ? ? ?
              << std::endl;
}

我有这样的代码。在Ubuntu 12.10和13.04下,它在Windows 8,g ++ 4.7和Clang ++ 3.2(x86和x64)下的MSVC 2012 x64下工作正常。但是,带有问号的行显示使用MinGW 4.7 x86 或MinGW 4.8 x64 编译时的未定义行为(抱歉,我以为我做过)。

调试器输出表示在此时链接到TargetClass的vtable存在问题。放置断点显示TargetClass :: operator string()加载了严重解除引用的对象。但是,使用显式的dynamic_cast会产生正确的输出。

我想知道什么可能导致这个问题。如果它是MinGW的一个bug,它可能会在它出现时立即解决,因为它打破了C ++的核心概念之一。

3 个答案:

答案 0 :(得分:4)

这是mingw gcc的一个已知问题。

不要使用虚拟继承,问题就会消失。

Bugtracker http://sourceforge.net/p/mingw/bugs/1679/

答案 1 :(得分:1)

这看起来像编译器错误(或dynamic_cast的运行时支持中的错误)。代码看起来是正确的,虽然我没有仔细挖掘它。当然,除非发布的代码不是产生问题的代码。

答案 2 :(得分:1)

我刚刚测试过:

  • 32位和64位MinGW-w64 GCC 4.6 / 4.7 / 4.8版本
  • MSVC 11.0和MSVC 11.0 11月CTP
  • 32位Clang 3.2使用GCC 4.6 libstdc ++

全部在Windows上,并且都提供输出:

1 2 3 4
1 2 3 4
1 2 3 4

与Linux上的Clang和GCC相同。

这是否是未定义的行为,我不确定。从未使用dynamic_cast