gpt4 book ai didi

c++ - 在 C++ 中,是否允许对象在其生命周期内合法地更改其类型?

转载 作者:可可西里 更新时间:2023-11-01 16:34:42 27 4
gpt4 key购买 nike

我有这个代码:

class Class {
public:
virtual void first() {};
virtual void second() {};
};

Class* object = new Class();
object->first();
object->second();
delete object;

我使用带有/O2 的 Visual C++ 10 进行编译并进行反汇编:

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 处,对象起始地址(存储 vptr 的位置)被复制到 esi 寄存器中。然后在 0040396E 这个地址用于检索 vptrvptr 值用于检索 first() 。然后在 00403976 再次检索 vptr 并用于检索 second() 的地址。

为什么 vptr 被检索了两次?对象是否可能在两次调用之间更改了其 vptr 还是只是优化不足?

最佳答案

Why is vptr retrieved twice? Could the object possible have its vptr changed in between calls or is it just an underoptimization?

考虑:

object->first();

这个调用可能会销毁对象并在同一 block 内存中创建一个新对象。因此,在此调用之后,无法对状态做出任何假设。例如:

#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:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • the storage for the new object exactly overlays the storage location which the original object occupied, and
  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
  • the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

上述代码不满足上述列表中的要求 2。

关于c++ - 在 C++ 中,是否允许对象在其生命周期内合法地更改其类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12472556/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com