2016-04-03 33 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++一般都有奇怪的分配和構造函數語義。爲什麼你想避免安置 - 無論如何呢? –