2010-10-25 91 views
10
SomeObj<unsigned int>* Buffer; 
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>)); 
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY]; 

當我踏上過去,這些線路與調試,它表明我的價值觀變量緩衝區和BufferPtr:放置新+陣列+排列

BufferPtr: 0x0d7f004c 
Buffer: 0x0d7f0050 

我真的不明白,爲什麼那些值不同。按照我的理解,放置new應該使用從地址'BufferPtr'開始的內存,以便在分配的內存上使用默認構造函數初始化數組元素,並返回指向數組中第一個元素的第一個字節的指針,這應該是與傳遞給placement new操作符完全相同的字節。

我理解錯了什麼,或者有人能告訴我爲什麼值不同?

謝謝!

//編輯:好的 - 我研究這個問題,並進一步得到了更多的混亂的結果:

int size = sizeof(matth_ptr<int>); 

    char* testPtr1 = (char*)malloc(a_resX*a_resY*sizeof(int)); 
    int* test1 = new(testPtr1) int[a_resX*a_resY]; 

    char* testPtr2 = mmgr::requestMemory(a_resX*a_resY*sizeof(int)); 
    int* test2 = new(testPtr2) int[a_resX*a_resY]; 

    char* testPtr3 = (char*)malloc(a_resX*a_resY*sizeof(matth_ptr<int>)); 
    matth_ptr<int>* test3 = new(testPtr3)matth_ptr<int>[a_resX*a_resY]; 

    char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr<int>)); 
    matth_ptr<int>* test4 = new(testPtr4)matth_ptr<int>[a_resX*a_resY]; 

調試器返回我下面的值我的變量:

size: 4 

testPtr1:0x05100418 
test1: 0x05100418 
testPtr2:0x0da80050 
test2: 0x0da80050 

testPtr3:0x05101458 
test3: 0x0510145c 
testPtr4:0x0da81050 
test4: 0x0da81054 

所以它必須清楚與我的通用智能指針類matth_ptr有關,所以它在這裏:

template <class X> class matth_ptr 
{ 
public: 
    typedef X element_type; 

    matth_ptr(){ 
     memoryOfst = 0xFFFFFFFF; 
    } 

    matth_ptr(X* p) 
    { 
     unsigned char idx = mmgr::getCurrentChunkIdx(); 
     memoryOfst = (int)p-(int)mmgr::getBaseAddress(idx); 
     assert(memoryOfst<=0x00FFFFFF || p==0);//NULL pointer is not yet handled 
     chunkIdx = idx; 
    } 
    ~matth_ptr()    {} 
    X& operator*()    {return *((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 
    X* operator->()    {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 
    X* get()     {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 


    template<typename T> 
    matth_ptr(const matth_ptr<T>& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers 
    template<typename T> 
    matth_ptr& operator=(const matth_ptr<T>& other) {memoryOfst = other.memoryOfst; return *this;} 
    template<typename T> 
    friend class matth_ptr; 
private: 

    union //4GB adressable in chunks of 16 MB 
    { 
     struct{ 
      unsigned char padding[3]; //3 bytes padding 
      unsigned char chunkIdx; //8 bit chunk index 
     }; 
     unsigned int memoryOfst; //24bit address ofst 
    }; 

}; 

任何人都可以解釋我發生了什麼事?謝謝!

+0

關閉我的頭頂,可能是對齊或虛擬空間。 – 2010-10-25 02:47:45

+0

是否意味着如果新建立的對象不像傳遞的地址對齊,那麼它只是在較高的內存地址處創建一個對象? – Mat 2010-10-25 02:50:08

+0

我會懷疑如此,雖然不確定。測試的一種方法是查看這是否發生在選定的內存位置(即強制giveMeSomeBytes給出對齊的地址)。 – 2010-10-25 02:51:50

回答

5

您正在使用new運算符的陣列版本,該運算符在您的實現中在內存分配的前幾個字節中存儲有關陣列大小的信息。

+0

和什麼時候是陣列版本的new運算符存儲這些字節,什麼時候它不這樣做?請在原始問題中檢查我的擴展測試。事實證明,使用'int'類型的地址不是缺省的,而是使用我自己的對象。 – Mat 2010-10-25 04:30:44

+0

數組大小是否存儲取決於對象類型是否具有析構函數,因爲delete []運算符必須調用每個對象的析構函數。 – Timo 2010-10-25 04:38:48

+0

因此 - 對於具有析構函數的對象,必須實際分配4個額外字節纔不會遇到麻煩?爲什麼教程討論陣列分配與放置新的不提這個?聽起來很重要... – Mat 2010-10-25 04:41:40

13

小心放置新的陣列。在目前的標準看第5.3.4.12,你會發現這一點:

new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f) 

很顯然,這將期望放置新的運營商來分配這額外的空間超出了數組的內容所需要的。 「y」僅被指定爲非負整數值。然後它將以這個數量抵消新功能的結果。

另請參見18.4.1.3.4它說的位置new操作符只是返回提供的指針。這顯然是預期的部分。

根據5.3.4.12,由於每次調用數組的偏移量可能不同,標準基本上意味着無法分配所需的確切大小。在實踐中,這個值可能是不變的,你可以將它添加到分配中,但是他的數量可能會在每個平臺上改變,並且每次調用都會按照標準說明。

+11

所以基本上這意味着 - 關於標準 - 陣列上的新放置不可用 – Mat 2010-10-25 18:13:11

+0

In預先分配數組的確切大小的條款:是的。請記住,您仍然可以創建一個定製的位置分配器,它在更大的內存塊上更像動態分配器。 – 2010-10-25 19:15:30

+0

請注意'operator new [](sizeof(T)* 5 + y,2,f)'是用戶定義的佈局ALLOCATION函數**,而'operator new [](sizeof(T)* 5,ptr)'是一個**非分配放置分配功能**。你在這裏看到的是另一個由「委員會」不小心總結的結果。我希望不遲於2020年完成清除。 – bit2shift 2017-02-16 06:21:12

1

正如其他人所說,這是由於您的C++實現將數組的大小存儲在您傳遞給數組佈局new的緩衝區的開始處。

一個簡單的解決方法是簡單地將數組指針指定給緩衝區,然後遍歷數組並使用常規(非數組)位置new來構造緩衝區中的每個對象。

2

@Mat,這實際上是一個很好的問題。當我使用placement new []時,我在刪除存儲時遇到了問題。即使我稱自己對稱放置刪除[],指針地址是而不是,與我自己的放置位置new []返回的相同。這使得貼圖new []完全無用,正如您在評論中所建議的那樣。

我發現的唯一解決方案是由Jonathan @提出的:不是放置new [],而是在數組的每個元素上使用放置new(非數組)。這對我來說很好,因爲我自己儲存大小。問題是我不得不擔心元素的指針對齊,新[]應該爲我做。

+1

有沒有這樣的事情作爲位置刪除運營商。當構造函數拋出放置new操作符時,放置delete *函數*會被調用,並且它什麼也不做。 請注意,'void *'放置new操作符意味着在給定的內存區域構造對象,而不是從堆中分配內存。因此,你*不能*使用運算符'delete'或'delete []'在由位置新數組構成的區域上,你需要保持數組的長度(聽起來很熟悉?)並遍歷數組並調用每個析構函數。 – bit2shift 2016-03-11 01:34:07