2015-06-19 53 views
0

我想分配一個結構數組,我希望每個結構對齊到64個字節。分配一個對齊的結構數組

我想這(這僅適用於Windows現在),但它不工作(我試圖用VS2012和VS2013):

struct __declspec(align(64)) A 
{ 
    std::vector<int> v; 

    A() 
    { 
     assert(sizeof(A) == 64); 
     assert((size_t)this % 64 == 0); 
    } 

    void* operator new[] (size_t size) 
    { 
     void* ptr = _aligned_malloc(size, 64); 
     assert((size_t)ptr % 64 == 0); 
     return ptr; 
    } 

    void operator delete[] (void* p) 
    { 
     _aligned_free(p); 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    A* arr = new A[200]; 
    return 0; 
} 

斷言((size_t)this % 64 == 0)符(模返回16)。它看起來像是在它的結構只包含簡單類型,但在包含容器(或其他一些std類)時破壞。

我做錯了什麼?有沒有辦法做到這一點? (最好是C++ 03兼容,但在VS2012中工作的任何解決方案都可以)。

編輯: 作爲暗示由Shokwav,這個工程:

A* arr = (A*)new std::aligned_storage<sizeof(A), 64>::type[200]; 
// this works too actually: 
//A* arr = (A*)_aligned_malloc(sizeof(A) * 200, 64); 
for (int i=0; i<200; ++i) 
    new (&arr[i]) A(); 

因此,它看起來像它涉及到使用新的[] ...我很好奇,如果任何人有一個解釋。

+0

http://en.cppreference.com/w/cpp/types/aligned_storage(C++ 11) – Shokwav

+0

按照你的編輯,你實際上調用「放置」新的運營商,它不工作(明顯)。然而,這很可能會流失,因爲沒有代碼,會調用A的析構函數數組中的每一項,即使你所說的「免費(ARR)」或「刪除ARR」 – xryl669

+0

這很好,我會打電話的析構函數手動:'arr [i]。〜A()' – Jerem

回答

0

我想知道爲什麼你需要這麼大的對齊要求,而且要在結構中存儲一個動態堆分配對象。但是,你可以這樣做:

struct __declspec(align(64)) A 
{ 
    unsigned char ___padding[64 - sizeof(std::vector<int>)]; 
    std::vector<int> v; 

    void* operator new[] (size_t size) 
    { 
     // Make sure the buffer will fit even in the worst case 
     unsigned char* ptr = (unsigned char*)malloc(size + 63); 

     // Find out the next aligned position in the buffer 
     unsigned char* endptr = (unsigned char*)(((intptr_t)ptr + 63) & ~63ULL); 
     // Also store the misalignment in the first padding of the structure 
     unsigned char misalign = (unsigned char)(endptr - ptr); 
     *endptr = misalign; 
     return endptr; 
    } 

    void operator delete[] (void* p) 
    { 
     unsigned char * ptr = (unsigned char*)p; 
     // It's required to call back with the original pointer, so subtract the misalignment offset 
     ptr -= *ptr; 
     free(ptr); 
    } 
}; 

int main() 
{ 
    A * a = new A[2]; 
    printf("%p - %p = %d\n", &a[1], &a[0], int((char*)&a[1] - (char*)&a[0])); 
    return 0; 
} 

,我沒有你的align_malloc和免費的功能,所以我提供了實現是這樣做的:

  1. 它分配較大的,以確保它適合在64字節的邊界
  2. 它計算從分配到最接近的64字節邊界的偏移量
  3. 它將「偏移量」存儲在第一個結構的填充中(否則我將需要每次更大的分配空間)
  4. 這是用來原來的指針計算回免費()

輸出:

0x7fff57b1ca40 - 0x7fff57b1ca00 = 64 

警告:如果在你的結構沒有填充,然後上面會損壞方案數據,因爲我將把misalignement偏移量存儲在將由內部成員的構造函數覆蓋的地方。 請記住,當您執行「new X [n]」時,「n」必須存儲在「某處」,因此在調用delete []時,將會執行對析構函數的「n」調用。通常,它存儲在返回的內存緩衝區之前(新的可能會分配所需的大小+4來存儲元素的數量)。這裏的計劃避免了這一點。

另一個警告:因爲C++調用該運營商,包括在尺寸存儲單元陣列的數一些額外的填充,你可能仍然得到您的對象在返回的地址指針「轉移」。你可能需要考慮它。這是std :: align所做的,它需要額外的空間,像我一樣計算對齊並返回對齊的指針。但是,由於在從new()返回之後發生的「計數存儲」移位,所以無法在新的[]超載中完成這兩個操作。但是,您可以通過一次分配來計算「計數存儲」空間,並在新的[]實施中相應地調整偏移量。

+0

如果你沒有實現標準庫,你不應該使用多個下劃線;) – Quentin

+0

如果我有2個下劃線,但是我有3個在這種情況下不在文件範圍)。無論如何,你可以使用任何你想要的填充名稱。 – xryl669

+0

我並不需要存儲在結構中一個std ::向量實際上,這只是一個例子。的64個字節對準也是在這種情況下的例子(儘管仍然可以以避免僞共享的處理器上操作的方式多線程的東西時,高速緩存行,其中有64個字節是有用的)。 – Jerem