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

Posted

技术标签:

【中文标题】这个钻石继承UB是MinGW中的一个错误吗?【英文标题】:Is this diamond inheritance UB a bug in MinGW? 【发布时间】:2013-05-31 22:28:23 【问题描述】:
#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;

我有这样的代码。它可以在 Windows 8 下的 MSVC 2012 x64、g++ 4.7 和 Clang++ 3.2(x86 和 x64)下在 Ubuntu 12.10 和 13.04 下按预期工作。然而,当使用 MinGW 4.7 x86 或 MinGW 4.8 x64 编译时,带问号的行显示了未定义的行为(对不起,我以为我做到了)。

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

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

【问题讨论】:

“未定义行为”是语言定义中的一个技术术语。这意味着语言定义没有说明会发生什么。如果您在运行代码时看到奇怪的事情发生,它不一定“表现出未定义的行为”。 正式地,代码需要#include &lt;string&gt; 在顶部的某个位置。这可能与问题无关。 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

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

【讨论】:

【参考方案3】:

我刚刚测试过:

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

【讨论】:

谢谢。我想知道我是否使用 Qt 包破坏了构建。 我想是这个:download.qt-project.org/official_releases/qt/5.0/5.0.1/…

以上是关于这个钻石继承UB是MinGW中的一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章

可以接受使用虚拟继承来防止意外创建钻石吗?

我的继承和有问题的“钻石继承”一样吗

如何从钻石继承中的不同类别中获取值

C ++中的非对称虚拟继承菱形

多级继承 C++

为啥这个钻石类继承输出不是我期望的?