2016-04-03 39 views
1
  • 我使用C++编译器是旧版本的实例化对象(C++ 98也许?)
  • 我不能动态地从使用的东西系统池分配内存像新的,malloc
  • 我可以使用内置的操作系统调用malloc从我定义的堆数组。

我遇到一些奇怪的行为(程序崩溃)当我这样做分配和从用户控制的存储器池

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 */   
    } 
} 

我看到的是,派生类的构造函数将被called..then其析构函数被调用然后崩溃。 我误以为* pMyPtr = cDclass()构造一个类,然后在pMyPtr指定的地址上创建该类的副本? 我这样说是因为当我删除 pMyPtr = cDClass() 并创建一个虚拟变量来存储cDclass的一个实例,然后使用memmove它不再崩溃。

回答

0
*pMyPtr = cDclass(); 

假定一个有效的对象已经存在于*pMyPtr,并使用其赋值运算符。 (在典型的实现,这可能是不够的,因为它不会复制vptr的。)

你需要什么,而不是为

new(pMyPtr) cDclass; 

调用构造函数在指定的内存位置。你需要#include <new>

+0

我不确定您需要包含“”才能使用展示位置新功能。 –

+0

@DavidHaim''是标准中唯一指定'operator new(size_t,void *)'的地方。如果你不使用任何头文件而使用它,g ++和clang ++都会抱怨。 – aschepler

0

第一个奇怪的是,这条线:

pMyPtr = myHeap[i * sizeof(cDclass) + 4]; 

编译毫无怨言。它隐含地将uchar_t转换为cDclass*,如果没有reinterpret_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 */   
    } 
} 

注意,您将负责实际调用析构函数为您创建的所有对象。

+0

有没有办法做到这一点,而不使用展示位置新?例如我可以做cDClass temp = cDClass(); (void)memmove(pMyPtr,&temp,sizeof(temp));这会成为一个安置新的并且完全安全的工作吗?这是我尝试的方法,它似乎工作..但我不相信它是完全安全的。 (在安置新闻之前,人们做了什么?) – Jason

+0

不,你不能。这就是新的展示位置。 AFAIK从C++开始就已经可用了,但早期的C++一般都有奇怪的分配和构造函数语义。为什么你想避免安置 - 无论如何呢? –