我正在反转一个我认为是用 MSVC 编译的程序。似乎每个 vtable 中的第一个条目是类的析构函数。但是,当我查看反汇编和反编译时,似乎析构函数都采用第二个参数,并且只有在第二个参数为非空时才释放对象的内存。
这第二个论点的目的是什么?我认为,如果它是一个析构函数,则应该始终销毁该类并释放其内存。那么为什么第二个参数可以禁止释放内存呢?
我正在反转一个我认为是用 MSVC 编译的程序。似乎每个 vtable 中的第一个条目是类的析构函数。但是,当我查看反汇编和反编译时,似乎析构函数都采用第二个参数,并且只有在第二个参数为非空时才释放对象的内存。
这第二个论点的目的是什么?我认为,如果它是一个析构函数,则应该始终销毁该类并释放其内存。那么为什么第二个参数可以禁止释放内存呢?
这些包装器在具有虚拟析构函数的类中使用以涵盖两种情况:
确保operator delete
在对象销毁后通过delete pClass;
语句调用正确的
删除通过new Class[N]
语句中的表达式分配的数组,delete [] class_array;
以确保使用正确的项目删除正确数量operator delete
并处理过程中的潜在异常
从我的旧文章:
当类有虚析构函数时,编译器会生成一个辅助函数——删除析构函数。它的目的是确保
operator delete
在销毁类时调用适当的。删除析构函数的伪代码如下所示:virtual void * A::'scalar deleting destructor'(uint flags) { this->~A(); if (flags&1) A::operator delete(this); };
这个函数的地址被放置在 vftable 中,而不是析构函数的地址。这样,如果另一个类覆盖了虚拟析构函数,
operator delete
则将调用该类的。尽管在实际代码中operator delete
很少被覆盖,因此通常您会看到对默认 delete() 的调用。有时编译器也可以生成一个向量删除析构函数。它的代码如下所示:
virtual void * A::'vector deleting destructor'(uint flags) { if (flags&2) //destructing a vector { array = ((int*)this)-1; //array size is stored just before the this pointer count = array[0]; 'eh vector destructor iterator'(this,sizeof(A),count,A::~A); if (flags&1) A::operator delete(array); } else { this->~A(); if (flags&1) A::operator delete(this); } };
有关更多详细信息,另请参阅Visual C++ 的主要开发人员之一 Jan Gray 的C++:Under the Hood。
我还建议您使用自定义运算符 new/delete 制作一些类并检查生成的代码。