sha*_*oth 9 c++ polymorphism virtual-functions rtti visual-c++
我有这个代码:
class Class {
public:
virtual void first() {};
virtual void second() {};
};
Class* object = new Class();
object->first();
object->second();
delete object;
Run Code Online (Sandbox Code Playgroud)
用Visual C++ 10和/ O2编译并进行反汇编:
282: Class* object = new Class();
00403953 push 4
00403955 call dword ptr [__imp_operator new (4050BCh)]
0040395B add esp,4
0040395E test eax,eax
00403960 je wmain+1Ch (40396Ch)
00403962 mov dword ptr [eax],offset Class::`vftable' (4056A4h)
00403968 mov esi,eax
0040396A jmp wmain+1Eh (40396Eh)
0040396C xor esi,esi
283: object->first();
0040396E mov eax,dword ptr [esi]
00403970 mov edx,dword ptr [eax]
00403972 mov ecx,esi
00403974 call edx
284: object->second();
00403976 mov eax,dword ptr [esi]
00403978 mov edx,dword ptr [eax+4]
0040397B mov ecx,esi
0040397D call edx
285: delete object;
0040397F push esi
00403980 call dword ptr [__imp_operator delete (405138h)]
Run Code Online (Sandbox Code Playgroud)
请注意,在00403968对象的地址开始(vptr存储的位置)被复制到esi寄存器中.然后在0040396E此地址用于检索vptr并且该vptr值用于检索地址first().然后,在00403976将vptr被恢复和重新用于检索的地址second().
为什么vptr被检索两次?这个对象可能vptr在两次调用之间有所改变,还是仅仅是一个不优化?
为什么vptr被检索两次?这个对象可能在调用之间改变了它的vptr,还是只是一个欠优化?
考虑:
object->first();
Run Code Online (Sandbox Code Playgroud)
此调用可能会破坏对象并在同一块内存中创建一个新对象.因此,在此调用之后,不能对状态做出任何假设.例如:
#include <new>
struct Class {
virtual void first();
virtual void second() {}
virtual ~Class() {}
};
struct OtherClass : Class {
void first() {}
void second() {}
};
void Class::first() {
void* p = this;
static_assert(sizeof(Class) == sizeof(OtherClass), "Oops");
this->~Class();
new (p) OtherClass;
}
int main() {
Class* object = new Class();
object->first();
object->second();
delete object;
}
Run Code Online (Sandbox Code Playgroud)
如果该函数是内联的和/或使用链接时代码生成,则编译器可以优化掉不必要的寄存器加载.
由于DeadMG和Steve Jessop注意到上面的代码表现出不确定的行为.根据C++ 2003标准的3.8/7:
如果在对象的生命周期结束之后并且在重用或释放对象占用的存储之前,则在原始对象占用的存储位置创建新对象,指向原始对象的指针,引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用来操纵新对象,如果:
- 新对象的存储完全覆盖原始对象占用的存储位置,以及
- 新对象与原始对象的类型相同(忽略顶级cv限定符),和
- 原始对象的类型不是const限定的,如果是类类型,则不包含任何类型为const限定的非静态数据成员或引用类型,以及
- 原始对象是类型为T的派生程度最高的对象(1.8),新对象是类型为T的派生程度最高的对象(也就是说,它们不是基类子对象).
上述代码不满足上述列表中的要求2.
| 归档时间: |
|
| 查看次数: |
301 次 |
| 最近记录: |