从用户控制的内存池中分配和实例化对象 Li >我使用的C++编译器是一个旧版本(C++ 98可能?) 我不能使用诸如new、malloc之类的东西从系统池动态分配内存 但是,我可以从自己定义的堆数组中使用内置操作系统调用malloc
当我执行以下操作时,我遇到了一些奇怪的行为(程序崩溃)从用户控制的内存池中分配和实例化对象 Li >我使用的C++编译器是一个旧版本(C++ 98可能?) 我不能使用诸如new、malloc之类的东西从系统池动态分配内存 但是,我可以从自己定义的堆数组中使用内置操作系统调用malloc,c++,placement-new,C++,Placement New,当我执行以下操作时,我遇到了一些奇怪的行为(程序崩溃) class cBaseClass /* pure abstract */ { public: virtual void ifFunc( void ) = 0; virtual ~cBaseClass() = 0; } inline cBaseClass::~cBaseClass() { } class cDclass:cBaseClass { public: cDclass(); ~cDclass(); void ifFunc( voi
class cBaseClass /* pure abstract */
{
public:
virtual void ifFunc( void ) = 0;
virtual ~cBaseClass() = 0;
}
inline cBaseClass::~cBaseClass()
{
}
class cDclass:cBaseClass
{
public:
cDclass();
~cDclass();
void ifFunc( void ); /* implement the pure virtual */
}
cDclass::cDclass( void )
{
printf("[0x%X] derived constructor called\n", this);
}
cDclass::~cDclass( void )
{
printf("[0x%X] derived destructor called\n", this);
}
void cDclass::ifFunc(void)
{
printf("[0x%X] ifFunc called from derived class\n", this);
}
uchar_t myHeap[4096];
int main ( void )
{
cDclass* pMyPtr = NULL;
uint32_t i = 0;
( void ) memset( myHeap, 0, sizeof(myHeap)/sizeof(myHeap[0]);
for( i = 0; i < 20; i++)
{
pMyPtr = myHeap[i * sizeof(cDclass) + 4];
*pMyPtr = cDclass();
pMyPtr->ifFunc(); /* Crash */
}
}
class cBaseClass/*纯抽象*/
{
公众:
虚空ifFunc(void)=0;
virtual~cBaseClass()=0;
}
内联cBaseClass::~cBaseClass()
{
}
类别Cclass:cBaseClass
{
公众:
cDclass();
~cDclass();
void ifFunc(void);/*实现纯虚拟*/
}
cDclass::cDclass(void)
{
printf(“[0x%X]名为\n”的派生构造函数,此);
}
cDclass::~cDclass(无效)
{
printf(“[0x%X]名为\n的派生析构函数”,这是);
}
void cDclass::ifFunc(void)
{
printf(“[0x%X]从派生类调用的ifFunc\n”,this);
}
uchar_t myHeap[4096];
内部主(空)
{
cDclass*pMyPtr=NULL;
uint32_t i=0;
(void)memset(myHeap,0,sizeof(myHeap)/sizeof(myHeap[0]);
对于(i=0;i<20;i++)
{
pMyPtr=myHeap[i*sizeof(cDclass)+4];
*pMyPtr=cDclass();
pMyPtr->ifFunc();/*崩溃*/
}
}
我看到的是,派生类的构造函数被调用..然后它的析构函数被调用,然后崩溃。
我是否错误地认为*pMyPtr=cDclass()构造一个类,然后在pMyPtr指定的地址复制该类?
我这样说是因为当我移除
pMyPtr=cDClass()
并创建一个伪变量来存储cDclass的实例,然后使用memmove,这样就不会再崩溃
*pMyPtr = cDclass();
假设有效对象已存在于*pMyPtr
并使用其赋值运算符。(在典型实现中,这可能不够好,因为它不复制vptr。)
你需要的是
new(pMyPtr) cDclass;
在指定的内存位置调用构造函数。您需要#include
假设有效对象已存在于*pMyPtr
并使用其赋值运算符。(在典型实现中,这可能不够好,因为它不复制vptr。)
你需要的是
new(pMyPtr) cDclass;
要在指定的内存位置调用构造函数,您需要
#include
第一件奇怪的事情是这一行:
pMyPtr = myHeap[i * sizeof(cDclass) + 4];
编译时没有抱怨。它隐式地将uchar\u t
转换为cDclass*
,如果没有reinterpret\u cast
,这应该是不可能的。但可能是您的编译器在那里更为宽松。无论如何,至少您缺少了&
操作符
第二个问题是,您的假设是错误的。行所做的是在堆栈上构造一个临时对象,然后假设在指针位置已经有一个完全构造的对象,调用该对象的编译器生成的复制赋值运算符,并将该临时对象作为参数,然后销毁该临时对象
永远不会发生的事情是,一个对象实际上是在内存中构造的。这意味着vptr永远不会初始化,因此对虚拟函数的调用是空的取消引用
您需要做的是使用placement new在适当的位置构造对象。您的循环应如下所示:
int main ( void )
{
uint32_t i = 0;
( void ) memset( myHeap, 0, sizeof(myHeap)/sizeof(myHeap[0]);
for( i = 0; i < 20; i++)
{
// get the address to construct the object at
uchar_t* pMyAddr = &myHeap[i * sizeof(cDclass) + 4];
// construct a new object in-place at that address
cDclass* pMyPtr = new (pMyAddr) cDclass();
pMyPtr->ifFunc(); /* Don't crash */
}
}
int main(无效)
{
uint32_t i=0;
(void)memset(myHeap,0,sizeof(myHeap)/sizeof(myHeap[0]);
对于(i=0;i<20;i++)
{
//获取要在其中构造对象的地址
uchar_t*pMyAddr=&myHeap[i*sizeof(cDclass)+4];
//在该地址构建一个新对象
cDclass*pMyPtr=new(pMyAddr)cDclass();
pMyPtr->ifFunc();/*不要崩溃*/
}
}
请注意,您将负责为您创建的所有对象实际调用析构函数。第一件奇怪的事情是这行:
pMyPtr = myHeap[i * sizeof(cDclass) + 4];
编译时没有抱怨。它隐式地将uchar\u t
转换为cDclass*
,如果没有reinterpret\u cast
,这应该是不可能的。但可能是您的编译器在那里更为宽松。无论如何,至少您缺少了&
操作符
第二个问题是,您的假设是错误的。行所做的是在堆栈上构造一个临时对象,然后假设在指针位置已经有一个完全构造的对象,调用该对象的编译器生成的复制赋值运算符,并将该临时对象作为参数,然后销毁该临时对象
永远不会发生的事情是,一个对象实际上是在内存中构造的。这意味着vptr永远不会初始化,因此对虚拟函数的调用是空的取消引用
您需要做的是使用placement new在适当的位置构造对象。您的循环应如下所示:
int main ( void )
{
uint32_t i = 0;
( void ) memset( myHeap, 0, sizeof(myHeap)/sizeof(myHeap[0]);
for( i = 0; i < 20; i++)
{
// get the address to construct the object at
uchar_t* pMyAddr = &myHeap[i * sizeof(cDclass) + 4];
// construct a new object in-place at that address
cDclass* pMyPtr = new (pMyAddr) cDclass();
pMyPtr->ifFunc(); /* Don't crash */
}
}
int main(无效)
{
uint32_t i=0;
(void)memset(myHeap,0,sizeof(myHeap)/sizeof(myHeap[0]);
对于(i=0;i<20;i++)
{
//获取要在其中构造对象的地址
uchar_t*pMyAddr=&myHeap[i*sizeof(cDclass)+4];
//在该地址构建一个新对象
cDclass*pMyPtr=new(pMyAddr)cDclass();
pMyPtr->ifFunc();/*不要崩溃*/
}
}
请注意,您将负责为您创建的所有对象实际调用析构函数。我不确定是否需要包含
才能使用placement new。@DavidHaim
是标准指定的运算符new(size\t,void*)的唯一位置
。如果您试图在不包含任何标题的情况下使用它,g++和clang++都会抱怨。我不确定您是否需要包含
才能使用placement new。@DavidHaim
是标准指定的运算符new(size\u t,void*)
。如果