一个对象允许在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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
