【发布时间】:2013-09-29 03:04:22
【问题描述】:
我的继承代码如下所示:
B
/ \
/ \
/ \
BI D
(template) /
\ /
\ /
DI
(template)
[B]ase 和[D]erived 是两个包含static 方法create() 的接口,该方法返回各自实现的实例BaseImpl 或DerivedImpl。
实现是模板,工厂方法选择如何在运行时实例化它们。下面的代码是我的程序逻辑的一个工作示例。
问题是,在我的真实代码中,Base 方法得到一个错误的this 指针并不可避免地崩溃。我在调用其中一个方法之前检查了汇编代码,该方法在实际代码和示例代码中都没有参数,发现它有所不同:
工作(示例)代码
call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov (%eax),%edx
add $0x8,%edx
mov (%edx),%edx
mov %eax,%ecx
call *%edx
以上转换为base->method() 调用,其中base 是std::unique_ptr<Base>。
对于那些不知道的人,类方法的调用约定可以是__thiscall,在这种情况下就是这样。这意味着this 不会在堆栈上传递,而是存储在ecx 中。上面的代码简单地将this存入ecx,然后定位method(),将其地址存入edx,并调用它。一切正常。
错误(真实)代码
call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov (%eax),%edx
add $0x18,%edx
mov (%edx),%ebx
lea -0x24(%ebp),%edx
mov %eax,(%esp)
movl $0x9,-0x9c(%ebp)
mov %edx,%ecx
call *%ebx
这是完全相同的base->method() 调用。这次将method()的地址存入ebx。但是,this 是从堆栈外的任意位置加载的!?正如预期的那样,该程序崩溃了。任何人都知道为什么编译器会生成这样的程序集?我还在想办法。
代码
示例代码如下。实际代码在类似于示例从invoker->invoke() 调用base->check() 时崩溃。
已删除代码以节省空间。要查看它,请检查编辑历史记录。
【问题讨论】:
-
this指针不必在不同的派生类中保持相同。如果需要最外层对象的基地址,可以使用dynamic_cast<const void *>iirc。 -
@AlanStokes 是的,你完全正确。我发布的代码不会重现我在真实代码中遇到的错误。实际代码中
this指针的地址超出了程序虚拟内存的范围,例如。0x429bce8与0x7a55ec。我会试着弄清楚发生了什么。 -
我已经更新了问题。
-
@n.m.它不是重复的。
标签: c++ mingw multiple-inheritance virtual-inheritance