关于 VTable 指针和 malloc

发布于 2024-12-08 15:37:26 字数 2391 浏览 4 评论 0原文

是否有任何独立于编译器且语法优雅的方法可以在使用 malloc 分配的对象中设置 vtable 指针?

我无法直接使用 new,因为我需要能够按需控制内存释放的流程,这需要使用 void ptr 来保存内存管理器中的内存位置,直到有足够的时间来释放。

class AbstractData
{
public:
   AbstractData() {}
   virtual ~AbstractData() {}

protected:
   virtual void SetData(int NewData) =0;
   virtual int GetData() const =0;
};

class ConcreteData : public AbstractData
{
protected:
   int Data;

public:
   ConcreteData() {}
   ~ConcreteData() {}

   void SetData(int NewData);
   int GetData() const;

};

void ConcreteData::SetData(int NewData) {Data=NewData;}

int ConcreteData::GetData() const 
{return Data;}

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    for (int x = 0; x < OBJ_NUMBER; x++)
       Test[x] = ConcreteData();

    Test[0]->GetData(); //Constructor was never called, vptr never initialized, crash

    free(Test);
    Test = NULL;
}

我希望本地副本有一个初始化的 vtable 指针,但可惜没有。 我知道如果您知道 vptr 的偏移量在哪里,您可以对 vptr 的偏移量进行依赖于编译器的取消引用,但此解决方案依赖于编译器,并且在许多分配中使用时不优雅。示例适用于 MSVC++ 8.0

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    ConcreteData StealVPtr();

    int* VPtr = *(int**)StealVPtr; 

    for (int x = 0; x < OBJ_NUMBER; x++)
       *(int**)Test[x] = VPtr;

    Test[0]->GetData(); //VPtr initialized in compiler dependent way

    free(Test);
    Test = NULL;
}

或者,可以使用放置 new,但它在语法上看起来再次不优雅,并且当它在 ptr 前面添加数组计数时,可能会导致带有析构函数的类型的数组偏移问题。

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    for (int x = 0; x < OBJ_NUMBER; x++)
    {
        if (!(ConcreteData* PlcTest = new(Test[x]) ConcreteData()))
        {
           free(Test);
           Test = NULL;
           return -1;
        }
    }

    PlcTest[0]->GetData(); //Constructor was invoked and VPtr was initialized

    for (int x = OBJ_NUMBER-1; x >= 0; x--)
        PlcTest[x].~ConcreteData();

    PlcTest = NULL;

    free(Test);
    Test = NULL;
}

这些真的是使用 malloc 初始化对象上的 VTable ptr/调用构造函数的唯一方法吗?

Is there any compiler independent and syntactically elegant way to set a vtable pointer in an object allocated with malloc?

I cannot use new directly as I need to be able to control the flow of memory releases on demand which requires the use of void ptrs to hold memory locations in a memory manager until there is ample time to release.

class AbstractData
{
public:
   AbstractData() {}
   virtual ~AbstractData() {}

protected:
   virtual void SetData(int NewData) =0;
   virtual int GetData() const =0;
};

class ConcreteData : public AbstractData
{
protected:
   int Data;

public:
   ConcreteData() {}
   ~ConcreteData() {}

   void SetData(int NewData);
   int GetData() const;

};

void ConcreteData::SetData(int NewData) {Data=NewData;}

int ConcreteData::GetData() const 
{return Data;}

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    for (int x = 0; x < OBJ_NUMBER; x++)
       Test[x] = ConcreteData();

    Test[0]->GetData(); //Constructor was never called, vptr never initialized, crash

    free(Test);
    Test = NULL;
}

I was hoping the local copy would have an initialized vtable pointer, but alas it does not.
I know you can do a compiler dependent dereference to the offset of the vptr if you know where it is, but this solution is compiler dependent and inelegant to use across many allocations. Example works with MSVC++ 8.0

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    ConcreteData StealVPtr();

    int* VPtr = *(int**)StealVPtr; 

    for (int x = 0; x < OBJ_NUMBER; x++)
       *(int**)Test[x] = VPtr;

    Test[0]->GetData(); //VPtr initialized in compiler dependent way

    free(Test);
    Test = NULL;
}

Alternatively, placement new could be used, but once again it looks syntactically inelegant and can cause array offsetting problems of types with destructors when it adds the array count in front of the ptr.

int main(int argc, char* argv[])
{
    int OBJ_NUMBER = 4;
    ConcreteData* Test = (ConcreteData*)malloc(OBJ_NUMBER*sizeof(ConcreteData));

    if (!Test)
        return -1;        

    for (int x = 0; x < OBJ_NUMBER; x++)
    {
        if (!(ConcreteData* PlcTest = new(Test[x]) ConcreteData()))
        {
           free(Test);
           Test = NULL;
           return -1;
        }
    }

    PlcTest[0]->GetData(); //Constructor was invoked and VPtr was initialized

    for (int x = OBJ_NUMBER-1; x >= 0; x--)
        PlcTest[x].~ConcreteData();

    PlcTest = NULL;

    free(Test);
    Test = NULL;
}

Are these really the only ways to initialize the VTable ptr/call constructors on objects using malloc?

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

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

发布评论

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

评论(2

陪你搞怪i 2024-12-15 15:37:26

您可能不知道您可以覆盖全局newdelete。请注意,您还需要重写 new[]delete[] 才能完成

下面是一个示例:

void * operator new( size_t size ) 
{
    return super_malloc( size );
}

You may not know that you can override global new and delete. Pay attention, you also need to override new[] and delete[] to be complete

Here an example:

void * operator new( size_t size ) 
{
    return super_malloc( size );
}
表情可笑 2024-12-15 15:37:26

您可以使用 placement new 运算符 在预分配的内存中构造类实例。

You could use the placement new operator to construct class instances in preallocated memory.

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