在没有 new[] 的情况下分配 Derived 数组:指向 Base vtable 的指针是错误的

发布于 2024-08-17 15:52:16 字数 1148 浏览 12 评论 0 原文

基本上,我有一个纯虚拟类 Base 和一个继承自 Base 的具体类 Derived 。然后,我分配一块内存,并通过简单的转换将其视为 Derived 数组。然后,我使用 = 填充数组。最后,我循环遍历该数组,尝试调用在 Base 中声明并在 Derived 中定义的虚拟方法 GetIndex。

问题是,我最终在尝试读取 Base 的 vtable 指针时遇到访问冲突异常(在 Visual Studio 调试中,这显示为 __vfptr,并且始终为 0xbaadf00d)。

以下是我遇到的问题的一个简单示例:

#include "stdafx.h"
#include "windows.h"

struct Base
{
    virtual int GetIndex() const = 0;
};

struct Derived : public Base
{
    int index;

    Derived()
    {
        static int test = 0;
        index = test++;
    }

    int GetIndex() const
    {
        return index;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    int count = 4;
    // Also fails with malloc
    Derived* pDerived = (Derived*)HeapAlloc(GetProcessHeap(), 0, sizeof(Derived) * count);

    for (int i = 0; i < count; i++)
    {
        Derived t;
        pDerived[i] = t;
    }

    // Should print 0 1 2 3
    for (int i = 0; i < count; i++)
    {
        Base& lc = pDerived[i];
        printf("%d\n", lc.GetIndex()); // FAIL!
    }
    return 0;
}

此行为仅在通过 HeapAlloc 或 malloc 分配内存时发生;如果使用 new[] ,则效果很好。 (此外,cstor 之前被调用了 4 次,因此输出为 4 5 6 7。)

Basically, I have a pure virtual class Base, and a concrete class Derived which inherits from Base. I then allocate a piece of memory and treat it as an array of Derived via a simple cast. Then, I populate the array using =. Finally, I loop through the array, trying to call the virtual method GetIndex that is declared in Base and defined in Derived.

The problem is that I end up getting an access violation exception trying to read the pointer to the vtable for Base (in Visual Studio debugging, this is shown as __vfptr, and it is always 0xbaadf00d).

Following is a simple example of the problem I am encountering:

#include "stdafx.h"
#include "windows.h"

struct Base
{
    virtual int GetIndex() const = 0;
};

struct Derived : public Base
{
    int index;

    Derived()
    {
        static int test = 0;
        index = test++;
    }

    int GetIndex() const
    {
        return index;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    int count = 4;
    // Also fails with malloc
    Derived* pDerived = (Derived*)HeapAlloc(GetProcessHeap(), 0, sizeof(Derived) * count);

    for (int i = 0; i < count; i++)
    {
        Derived t;
        pDerived[i] = t;
    }

    // Should print 0 1 2 3
    for (int i = 0; i < count; i++)
    {
        Base& lc = pDerived[i];
        printf("%d\n", lc.GetIndex()); // FAIL!
    }
    return 0;
}

This behavior only occurs when allocating the memory via HeapAlloc or malloc; if new[] is used, it works fine. (Also, the cstor is called 4 times previously, so the output is 4 5 6 7.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

许你一世情深 2024-08-24 15:52:16

如果您在没有 new 的情况下分配内存,则始终需要使用 placement new 和析构函数 x->~Derived();

If you allocate memory without new you always need to call the constructor manually with placement new and the destructor with x->~Derived();

遗忘曾经 2024-08-24 15:52:16

如果您想使用 C++ 默认分配器之外的分配器,您应该定义自己的运算符 new,而不是尝试记住每次都调用构造函数。

void *operator new[]( size_t block_size, HANDLE heap ) {
    return HeapAlloc( heap, 0, block_size );
}

...

Derived *pDerived = new( GetProcessHeap() ) Derived[ count ];

详细信息取决于您是否希望它成为分配 Derived 的默认方式以及它是否确实需要参数。

如果 free() 无法释放您获得的内存,您仍然需要小心。那么默认的 delete 将不起作用,您应该创建 Derived::operator delete 或编写自己的函数来调用 object->~Derived( )

If you want to use an allocator besides C++'s default, you should define your own operator new rather than try to remember to call the constructor every time.

void *operator new[]( size_t block_size, HANDLE heap ) {
    return HeapAlloc( heap, 0, block_size );
}

Derived *pDerived = new( GetProcessHeap() ) Derived[ count ];

Details depend on whether you want it to be the default way of allocating Derived and whether it really needs parameters.

You still need to be careful if free() can't free the memory you got. Then the default delete won't work, and you should either create Derived::operator delete or write your own function which calls object->~Derived().

何以笙箫默 2024-08-24 15:52:16

我认为在第一个 for 循环中,您正在创建一个没有 new 的对象。这意味着该对象的上下文是您的 for 循环。当退出 for 循环时,该变量不再存在。

I think inside the first for loop you are creating a object without new. Which means that the context of this object is your for loop. This variable no longer exists when you quit the for loop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文