2013-03-19 5 views

risposta

14

Se l'allineamento del tuo tipo non è sovra-allineato, allora sì, l'impostazione predefinita new funzionerà. "Sovra-allineato" significa che l'allineamento specificato in alignas è maggiore di alignof(std::max_align_t). L'impostazione predefinita new funzionerà più o meno con tipi non allineati per errore; l'allocatore di memoria predefinito assegnerà sempre la memoria con un allineamento uguale a alignof(std::max_align_t).

Se l'allineamento del tuo tipo è troppo allineato, sei sfortunato. Né il valore predefinito new, né alcun operatore globale new scritto, sarà in grado di conoscere l'allineamento richiesto per il tipo, per non parlare di allocare la memoria appropriata ad esso. L'unico modo per risolvere questo caso è sovraccaricare la classe operator new, che sarà in grado di interrogare l'allineamento della classe con alignof.

Naturalmente, questo non sarà utile se quella classe viene utilizzata come membro di un'altra classe. A meno che l'altra classe non sovraccarichi anche operator new. Quindi qualcosa di semplice come new pair<over_aligned, int>() non funzionerà.

Una proposta per C++ 17 (che è stata accettata) aggiunge support for dynamic allocation of over-aligned types, con sovraccarichi di operator new/delete che prendono il alignof del tipo assegnato. Ciò supporterà anche gli allineamenti inferiori al tipo max allineato, quindi l'allocatore di memoria non deve sempre restituire la memoria allineata a alignof(std::max_align_t).

Detto questo, i compilatori non sono richiesti per supportare tipi di sovradimensionamento.

+4

Per aggiungere: si può interrogare questo allineamento massimo tramite ' alignof (std :: max_align_t) '. I tipi con allineamenti maggiori di questo sono chiamati * sovra-allineati * e il loro supporto è condizionale, definito dall'implementazione. – GManNickG

+0

In realtà non ho bisogno di questo, comunque è bello saperlo comunque! – Skeen

+0

Si può fare qualcosa per aumentare il limite, per dire che l'allineamento massimo è in g ++? – Skeen

7

No, non è così. La struttura sarà riempita fino all'allineamento richiesto, ma non sarà allineata. C'è tuttavia la possibilità che questo sia allowed in C++17 (il fatto che questa proposta C++ 17 esista dovrebbe essere una prova abbastanza buona che non può funzionare in C++ 11).

Ho visto che questo sembra funzionare con alcuni allocatori di memoria, ma è stata pura fortuna. Ad esempio, alcuni allocatori di memoria allineeranno le loro allocazioni di memoria a potenze di 2 della dimensione richiesta (fino a 4KB) come ottimizzazione per l'allocatore (riduzione della frammentazione della memoria, possibilità di riutilizzare la memoria precedentemente liberata, ecc ...) . Tuttavia, le nuove implementazioni/malloc che sono inclusi nei sistemi OS X 10.7 e CentOS 6 che ho provato non fare questo e non riuscire con il seguente codice:

#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

Questo è corretto, la risposta più alta non lo è. C++ 11 * * fornirà l'allineamento corretto per gli oggetti allocati nello stack ma gli allocatori di memoria predefiniti non forniranno l'allineamento corretto. Quindi per ora, è necessario utilizzare le funzioni POSIX/Windows avvolte nelle macro di rilevamento del sistema operativo. Per esempio; posix_memalign su Linux/OSX/BSD e aligned_alloc su Windows. Per chi usa Intel MKL, ci sono mkl_malloc e mkl_free. – alfalfasprout