2013-03-19 10 views

Odpowiedz

14

Jeśli wyrównanie typu nie jest zbyt wyrównane, to tak, domyślny new zadziała. "Wyrównanie wyrównane" oznacza, że ​​wyrównanie określone w alignas jest większe niż alignof(std::max_align_t). Domyślnie new będzie działać z typami nieprostokątnymi mniej lub bardziej przypadkowo; domyślny alokator pamięci zawsze przydzieli pamięć z wyrównaniem równym alignof(std::max_align_t).

Jeśli jednak wyrównanie Twojego typu jest zbyt wyrównane, nie masz szczęścia. Ani domyślny new, ani żaden globalny operator new, który napiszesz, nie będą w stanie poznać wymaganego wyrównania typu, nie mówiąc już o przydzieleniu odpowiedniej dla niego pamięci. Jedynym sposobem, aby pomóc w tym przypadku, jest przeciążenie klasy operator new, która będzie w stanie zapytać o wyrównanie klasy z alignof.

Oczywiście nie będzie to przydatne, jeśli ta klasa jest używana jako członek innej klasy. Nie, chyba że ta druga klasa również przeciąży operator new. Coś tak prostego, jak new pair<over_aligned, int>() nie będzie działać.

Propozycja dla C++ 17 (która została zaakceptowana) dodaje support for dynamic allocation of over-aligned types, poprzez przeciążenia operator new/delete, które pobierają alignof typu, który jest przydzielany. Spowoduje to również wyrównanie wierszy mniejszych niż typ wyrównany do maksimum, więc przydział pamięci nie musi zawsze zwracać pamięci wyrównanej do alignof(std::max_align_t).

Mimo to kompilatory nie są wymagane w przypadku , aby w ogóle obsługiwać typy wyrównane.

+4

dodać: Można zapytać to maksymalne dopasowanie poprzez ' alignof (std :: max_align_t) '. Typy z wyrównaniem większym niż to nazywa się * over-wyrównane *, a ich obsługa jest warunkowa, definiowana przez implementację. – GManNickG

+0

Okazuje się, że tak naprawdę tego nie potrzebuję, mimo to dobrze jest wiedzieć! – Skeen

+0

Czy można zrobić coś, aby podnieść limit, aby uzyskać maksymalne wyrównanie w g ++? – Skeen

7

Nie, nie ma. Struktura zostanie dopełniona do żądanego wyrównania, ale nie zostanie wyrównana. Istnieje jednak szansa, że ​​będzie to allowed in C++17 (fakt, że ta propozycja C++ 17 powinna być całkiem dobrym dowodem, że to nie działa w C++ 11).

Widziałem, jak to działa z niektórymi alokatorami pamięci, ale to było szczęście. Na przykład, niektóre alokatory pamięci dopasują swoje przydziały pamięci do mocy 2 żądanego rozmiaru (do 4KB) jako optymalizację alokatora (zmniejszają fragmentację pamięci, prawdopodobnie ułatwiają ponowne wykorzystanie pamięci zwolnionej wcześniej, itp.) . Jednak nowe implementacje/malloc, które są zawarte w OS X 10.7 i CentOS 6 systemów, które testowałem nie rób tego i nie z następującego kodu:

#include <stdlib.h> 
#include <assert.h> 

struct alignas(8) test_struct_8 { char data; }; 
struct alignas(16) test_struct_16 { char data; }; 
struct alignas(32) test_struct_32 { char data; }; 
struct alignas(64) test_struct_64 { char data; }; 
struct alignas(128) test_struct_128 { char data; }; 
struct alignas(256) test_struct_256 { char data; }; 
struct alignas(512) test_struct_512 { char data; }; 

int main() { 
    test_struct_8 *heap_8 = new test_struct_8; 
    test_struct_16 *heap_16 = new test_struct_16; 
    test_struct_32 *heap_32 = new test_struct_32; 
    test_struct_64 *heap_64 = new test_struct_64; 
    test_struct_128 *heap_128 = new test_struct_128; 
    test_struct_256 *heap_256 = new test_struct_256; 
    test_struct_512 *heap_512 = new test_struct_512; 

#define IS_ALIGNED(addr,size) ((((size_t)(addr)) % (size)) == 0) 

    assert(IS_ALIGNED(heap_8, 8)); 
    assert(IS_ALIGNED(heap_16, 16)); 
    assert(IS_ALIGNED(heap_32, 32)); 
    assert(IS_ALIGNED(heap_64, 64)); 
    assert(IS_ALIGNED(heap_128, 128)); 
    assert(IS_ALIGNED(heap_256, 256)); 
    assert(IS_ALIGNED(heap_512, 512)); 

    delete heap_8; 
    delete heap_16; 
    delete heap_32; 
    delete heap_64; 
    delete heap_128; 
    delete heap_256; 
    delete heap_512; 

return 0; 
} 
+0

To prawda, najlepsza odpowiedź nie jest. C++ 11 * * da ci prawidłowe wyrównanie dla obiektów przydzielonych do stosu, ale domyślne alokatory pamięci nie dadzą prawidłowego wyrównania. Na razie musisz używać funkcji POSIX/windows owiniętych w makra wykrywające system operacyjny. Na przykład; posix_memalign w systemach Linux/OSX/BSD i aligned_alloc w systemie Windows. Dla osób używających Intel MKL dostępne są mkl_malloc i mkl_free. – alfalfasprout

Powiązane problemy