一个对象允许在C的生命周期内合法改变其类型吗?
我有这个代码:
class Class { public: virtual void first() {}; virtual void second() {}; }; Class* object = new Class(); object->first(); object->second(); delete object; 我用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)] 请注意,在00403968,将对象start(其中存储vptr的地址)复制到esi寄存器中.然后在0040396E,该地址用于检索vptr,并使用vptr值来检索first()的地址.然后在00403976再次检索vptr,并用于检索second()的地址. 为什么vptr检索两次?可能的对象可能会在调用之间改变其vptr,还是只是一个低优化? 解决方法
考虑: object->first(); 此调用可能会破坏对象并在同一内存块中创建一个新的对象.因此,在这个呼吁之后,不能对国家作出任何假设.例如.: #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; } 如果使用内联函数和/或链接时代码生成,编译器可以优化不必要的寄存器负载. 正如DeadMG和Steve Jessop所说,上述代码展现了未定义的行为.根据C 2003标准的3.8 / 7:
上述代码不符合上述列表中的要求2. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |