C++ 虚拟继承、虚拟析构函数和 dynamic_cast<void*>

标签 c++

我试图理解为什么第二个断言在以下代码中失败(如果重要,通过 Visual Studio 2019 使用 MSVC):

#include <cstdlib>

class grandparent
{
public:
    virtual ~grandparent() {};
};

class parent : public virtual grandparent 
{};

class child : public parent
{};

int main() 
{
    void* mem = malloc(sizeof(child));
    child* c = new (mem) child;
    assert(dynamic_cast<void*>(c) == mem); // ok
    std::destroy_at(c);
    assert(dynamic_cast<void*>(c) == mem); // fails
}

据我了解,dynamic_cast<void*>在指向多态类型的指针上返回该指针的最派生类型的地址。这在通过 std::destroy_at 销毁之前效果很好.但是在销毁后它不再提供指向最初分配的内存的指针,但我不明白为什么。

所以我的问题是:

  1. 如何dynamic_cast<void*>努力获取给定指针的最派生类型的地址?
  2. 析构函数做了什么以改变什么 dynamic_cast<void*>返回?

在四处搜索和 self 教育的过程中,我在有关 vtables 的系列博文中找到了以下博文:https://shaharmike.com/cpp/vtable-part4/ .在博文中有一段关于析构函数的简短介绍:

Here's a quick thought-exercise: why do destructors change the vtable pointer to point to the their own class’s rather than keep it pointing to the concrete class? Answer: Because by the time the destructor runs, any inheriting class had already been destroyed. Calling such class’s methods is not something you want to do.

据此,我的一个猜测是 dynamic_cast<void*>通过查看给定指针的 vtable 来工作,就像引用所说的那样,析构函数在调用时更改 vtable 指针。这样对吗?如果是这样,我想确切地了解下面发生的事情,因此在这方面提供进一步阅读的任何解释或资源将不胜感激。

最佳答案

  1. How does dynamic_cast<void*> work in getting the address of the most derived type of the given pointer?

如何 dynamic_cast实现其要求取决于语言的特定实现。实际上,一些数据必须与对象一起存储。此数据称为运行时类型信息

  1. What does the destructor do such that it changes what dynamic_cast returns?

当然,它会破坏对象。对象的生命周期已经结束。使用 dynamic_cast 的行为在对象生命周期之外指向对象的指针是未定义的(在析构/构造时使用它有特殊规则)。

标准说(引用最新草案)

[basic.life]

... The lifetime of an object o of type T ends when:

  • if T is a class type, the destructor call starts

... after the lifetime of an object has ended and before the storage which the object occupied is reused or released, ... The program has undefined behavior if:

  • ...
  • the pointer is used as the operand of a dynamic_­cast ([expr.dynamic.cast]).

关于C++ 虚拟继承、虚拟析构函数和 dynamic_cast<void*>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57828267/

相关文章:

c++ - 在 OpenCV 中为我检测到的对象制作动画

c++ - 是否应该为没有副作用的丢弃值表达式发出诊断?

c++ - 将派生类视为基类 - 它如何帮助我们避免编写更多代码?

c++ - 如何忽略参数包参数

c++ - OpenCV - 从 BGRA 输出创建 CV_8UC3(3 channel )垫

c++ - 获取文件路径的一部分

c++ - Qt 添加 Widget 到 GraphicsView?

C++程序有语法错误,第一次使用模块

c++ - 蓝牙设备本地名称

java - 在 openframeworks 中使用 android UI 修改 C++ 程序中的变量?