2013-07-25 14 views
6

C++ 11 fornisce la classe std::allocator_traits come il modo standard per utilizzare allocatori. La funzione statica std::allocator_traits::construct() richiede un puntatore al quale deve essere costruito l'oggetto. La funzione statica std::allocator_traits::allocate(), tuttavia, restituisce un valore allocator::pointer, che ha solo comportarsi come un puntatore ma non è necessariamente uno (in generale, anche se std::allocator::pointer è necessario per essere un puntatore).allocator_traits :: costrutto (vs) allocator_traits :: allocare()

Come si può suppone di utilizzare i metodi statici di allocazione e di costruzione se, in generale, che lavoreranno con i tipi incompatibili? Possono essere utilizzati solo se il tipo pointer è effettivamente convertibile in un normale puntatore semplice?

+0

+1 Questa è una domanda eccezionalmente perspicace in questo momento. Ci sono pochissimi programmatori C++ che esplorano queste acque. Gli implementatori devono. Il che mi porta a porre la domanda: sei un implementatore di std :: lib? –

+0

@HowardHinnant: Grazie! La domanda è connessa alla progettazione di una piccola classe vettoriale con un paio di campane e fischi extra rispetto a '' std :: vector'' (ad esempio, l'uso automatico dell'archiviazione statica fino a pochi elementi, il supporto per SSE e altre istruzioni vettoriali , eccetera.). Volevo solo provare a fare le cose nel modo "corretto" rispetto al supporto degli allocatori. – bluescarni

risposta

4

Ci sono due tecniche per fare questo a seconda di ciò che avete in questo momento.

Se si dispone di un'espressione lvalue, dire che il campo di valore in un nodo, quindi è possibile utilizzare std :: AddressOf in questo modo:

allocator_traits<allocator_type>::construct(alloc, std::addressof(ptr->value), ...); 

dove ptr è un allocator_type::pointer.

Tuttavia, se non si dispone di un campo per dereference e si desidera convertire un allocator_type::pointer-T*, c'è un trucco è necessario implementare prima:

template <class T> 
inline 
T* 
to_raw_pointer(T* p) noexcept 
{ 
    return p; 
} 

template <class Pointer> 
inline 
typename std::pointer_traits<Pointer>::element_type* 
to_raw_pointer(Pointer p) noexcept 
{ 
    return p != nullptr ? ::to_raw_pointer(p.operator->()) 
         : nullptr; 
} 

E ora si può dire:

allocator_traits<allocator_type>::construct(alloc, to_raw_pointer(ptr), ...); 
+0

Oh wow, non si finisce mai di imparare ... La semantica di '' operator ->() '' è piuttosto sconvolgente: D – bluescarni

+0

Applausi a proposito, risposta contrassegnata come accettata. – bluescarni

+0

perché scrivi '::' davanti a 'to_raw_pointer (p.operator ->())'? C'è il pericolo che ADL causi interferenze altrimenti, o è solo un'abitudine? Presumo che quando entrambi i sovraccarichi si trovano nello stesso spazio dei nomi non avrebbe importanza. – TemplateRex