从用户控制的内存池中分配和实例化对象 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*)
。如果