关于 VTable 指针和 malloc
是否有任何独立于编译器且语法优雅的方法可以在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能不知道您可以覆盖全局
new
和delete
。请注意,您还需要重写new[]
和delete[]
才能完成下面是一个示例:
You may not know that you can override global
new
anddelete
. Pay attention, you also need to overridenew[]
anddelete[]
to be completeHere an example:
您可以使用 placement new 运算符 在预分配的内存中构造类实例。
You could use the placement new operator to construct class instances in preallocated memory.