c++ - MSVC 中的虚拟继承错误

标签 c++ visual-studio

看来我的问题是 MSVC 中的错误。我正在使用带有 Service Pack 1 的 Visual Studio 2008,并且我的代码适用于 GCC(在 codepad.org 上测试过)。

关于这个错误的任何官方信息?任何想法如何解决它? VS2010中的bug修复了吗?我们将不胜感激所有见解。

代码:

struct Base {
    Base(int i = 0) : i(i) {}
    virtual ~Base() {}
    virtual Base *clone() const = 0;

protected:
    int i;
};

struct A : virtual public Base {
    A() {}
    virtual A *clone() const = 0;
};

struct B : public A {
    B() {}
    B *clone() const { return new B(*this); }

    /// MSVC debugger shows that 'b' is for some reason missing the Base
    /// portion of it's object ("Error: expression cannot be evaluated")
    /// and trying to access 'b.i' causes an unhandled exception.
    ///
    /// Note: This only seems to occur with MSVC
    B(const B &b) : Base(b.i), A() {}
};

void foo(const A &elem) {
    A *a = elem.clone();
    if (a) delete a;
}

int main() {
    A *a = new B;
    foo(*a);
    delete a;
}

最佳答案

当通过 A::clone 调用时,编译器似乎没有正确调整 this 指针。如果您删除 A::clone 的声明,那么一切正常。

深入挖掘,当你有 A::clone 时,vtable 看起来像这样:

    [0x0]   0x002f1136 [thunk]:B::`vector deleting destructor'`vtordisp{4294967292,0}' (unsigned int)   void *
    [0x1]   0x002f11e0 [thunk]:B::clone`vtordisp{4294967292,0}' (void)  void *
    [0x2]   0x002f12ad [thunk]:B::clone`vtordisp{4294967292,4}' (void)  void *
    [0x3]   0x002f12a3 B::clone(void)   void *

而 foo 调用 elem.__vfptr[2],将 this 错误地偏移了 -4 个字节。如果没有 A::clone,vtable 看起来像这样:

    [0x0]   0x00ee1136 [thunk]:B::`vector deleting destructor'`vtordisp{4294967292,0}' (unsigned int)   void *
    [0x1]   0x00ee11e0 [thunk]:B::clone`vtordisp{4294967292,0}' (void)  void *
    [0x2]   0x00ee12a3 B::clone(void)   void *

而 foo 调用 elem.__vfptr[1]。这根本不会调整 this (并且代码假定 this 将等于 Base 而不是 B )。

所以看起来编译器假设 A::clone 是一个新的虚拟方法,并且在确定 A 需要一个新的虚拟表,但后来一些其他代码确定 A 不需要一个虚拟表。您可以通过比较 sizeof(B) 有无新虚函数来验证这一点:

struct A : virtual public Base {
    A() {}
    virtual A *clone() const = 0;
}; //sizeof(B)==16

struct A : virtual public Base {
    A() {}
    virtual A *clone() const = 0;
virtual const A *clone2() const { return this; }
}; //sizeof(B)==20

所以这是一个编译器错误。

关于c++ - MSVC 中的虚拟继承错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2240669/

相关文章:

c++ - 类型 T 的多个别名

c++ - C++ 中带有换行符的 printf 的奇怪行为

c++ - 如何在 C++ 中定义 vector <boost::mutex>?

c++ - 未命中断点但已加载符号

c# - Visual Studio 在运行 Xamarin 应用程序时无法找到 .NET.Core SDK

visual-studio - Visual Studio - 删除资源后缺少菜单项和工具栏按钮

c++ - 为什么 std::strcpy 仍然适用于像 char copyTo[0] 这样的目的地?

c++ - Multimap 和 shared_ptr

c# - 为运行时或编译时引用所有必需的程序集?

c# - 如何获取类别或子类别中的所有产品