2013-03-05 15 views
10

Stavo cercando di utilizzare un allocatore personalizzato per std::vector<char>, ma ho notato che std::vector non ha bisogno/utilizzare alcuna delle funzioni membro dal mio allocatore. Com'è possibile?L'allocatore personalizzato per std :: vector <char> viene ignorato

#include <vector> 

struct A : private std::allocator<char> { 
    typedef std::allocator<char> alloc; 
    using alloc::value_type; 
    using alloc::pointer; 
    using alloc::const_pointer; 
    using alloc::difference_type; 
    using alloc::size_type; 
    using alloc::rebind; 
    // member functions have been removed, since the program compiles without them 
}; 

int main() { 
    std::vector<char, A> v; 
    v.resize(4000); 
    for (auto& c : v) 
     if (c) 
     return 1; // never happens in my environment 
    return 0; // all elements initialized to 0. How is this possible? 
} 

Stavo cercando il programma di cui sopra con una linea C++ 11 compilatore (LiveWorkSpace), fornendo g ++ 4.7.2, 4.8 e 4.6.3.

Fondamentalmente allocate(), deallocate(), construct() e destroy() non sono definiti nel mio allocator, ma il programma viene compilato e tutti gli elementi vengono inizializzati a 0.

risposta

14

La libreria standard GCC sarà sempre associare nuovamente l'allocatore in dotazione in modo internamente lo fa qualcosa di simile (in C++ 03):

typedef Alloc::template rebind<value_type>::other _Allocator_type; 

(In C++ 11 utilizza allocator_traits ma in questo caso la il risultato è lo stesso.)

Il vettore quindi memorizza internamente un oggetto di quel tipo e lo utilizza per tutti (de) l'allocazione.

Dato che non è stato definito un modello membro rebind nell'assegnatore, è stato appena ridichinato quello della classe base, il risultato della riconnessione è std::allocator<value_type> e non il proprio tipo. std::allocator fornisce ovviamente tutte queste funzioni, quindi quelle utilizzate, indipendentemente dal fatto che vengano definite sul proprio tipo.

È possibile risolvere il problema con l'aggiunta di questo al vostro allocatore intead di using alloc::rebind; in modo che vector memorizza e utilizza un A internamente:

struct A : private std::allocator<char> { 
    template<typename U> 
     struct rebind { 
     typedef A other; 
     }; 

N.B. ciò funzionerà solo per vector, perché vector non ha strettamente bisogno di riassociare l'allocatore (gli utenti sono obbligati a creare un'istanza del modello con allocator<value_type>, ma GCC's vector rebinds comunque in modo che se gli utenti istanziano vector<int, std::allocator<char>> funzioni ancora.) Per contenitori basati su nodo come std::set l'allocatore deve essere un modello che può essere rimbalzato, perché il contenitore deve allocare i suoi tipi di nodi interni, non lo value_type, quindi è necessario che Alloc::rebind<internal_node_type>::other sia valido.

+1

In realtà, perché è preferibile che funzioni ancora se l'utente fornisce un 'std :: allocator ' come allocatore per un 'vector '? Non ha più senso ottenere un errore del compilatore? –

+1

Non sono sicuro che sia desiderabile personalmente, ma è sempre stato così. Per altri contenitori ha più senso: se un utente dice 'std :: map , std :: allocator >>' è una comodità accettarlo anche se tecnicamente l'allocatore deve essere 'std :: allocator >' –

+5

@AndyProwl - gli allocatori in realtà dovrebbero essere parametri template template, ma i parametri template template non esistevano al momento STL (NOTA: ** STL **, non ** Standard Library **) è stato progettato, quindi 'rebind' è stato creato. –

7

vector verrà riassociare l'allocatore. Quando lo si porta in ambito da std::allocator, A::rebind<T>::other sarà semplicemente std::allocator<T>. Quindi tutto funziona bene.

Problemi correlati