看来我的问题是 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/