在没有new []的情况下分配Derived数组:指向Base vtable的指针很糟糕

时间:2010-01-11 19:51:51

标签: c++ inheritance dynamic-memory-allocation vtable

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

问题是我最终得到一个访问冲突异常,试图读取指向vtable for Base的指针(在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。)

3 个答案:

答案 0 :(得分:9)

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

进行析构函数调用

答案 1 :(得分:1)

如果你想使用除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()的自己的函数。

答案 2 :(得分:0)

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