2011-11-13 18 views
5

contenitori STL hanno un reference e const_referencetypedef, che, in molti casi che ho visto (contenitori di bool essendo le uniche eccezioni mi viene in mente), potrebbe essere banalmente definito comeCome si comporta esattamente il typedef 'reference'?

typedef value_type& reference; 
typedef const value_type& const_reference; 

cosa esattamente, tuttavia , la semantica di questi tipi?

Da quello che ho capito, si suppone che "si comportino come riferimenti al tipo di valore", ma cosa significa esattamente?

MSDN dice che è reference:

Un tipo che fornisce un riferimento a un elemento memorizzato in un vettore.

Ma cosa significa esattamente? Hanno bisogno di sovraccaricare operatori specifici o avere un comportamento specifico? Se sì, qual è il comportamento richiesto?

+2

Non penso che nessuno stia capendo questa domanda. Sta chiedendo a cosa si deve comportare il tipo detto "riferimento". Non il tipo di riferimento C++ (come 'int &'). –

+0

Ripensandoci, non credo di aver capito la Q. Il tipo 'reference' o' const_reference' si comporta come un normale riferimento o const riferimento, perché pensi che dovrebbe comportarsi in modo diverso? –

+0

@Als: La domanda, letteralmente, è: cosa significa "si comporta come un riferimento normale"? È una frase vaga di per sé, quindi non so quali condizioni dovrei soddisfare prima che il mio tipo "si comporti come un riferimento normale" (se stessi creando un contenitore, ad esempio). – Mehrdad

risposta

1

quello che stai chiedendo è "Posso sempre dereferenziare un riferimento? E sì, è possibile. Ciò significa Dereferenced reference può fare tutto dereferenziato value_type& può fare, che è tutto value_type può fare. Se questo ha un senso per voi.


non si può sovraccaricare gli operatori sul typedef. typedef hanno lo stesso comportamento come il tipo a cui sono assegnati. il motivo per cui sono typedef è quello di renderli meno ingombranti e di fornire una "interfaccia" comune

Il motivo reference esiste per evitare che cose come questa:

template<typename T> 
struct foo { 
    T& bar(); 

    typedef T& reference; 
    reference baz(); 
} 

foo<int> x; 
foo<int>::T& y = x.bar(); // error! returns a T& but I can't create one! 
foo<int>::reference z = x.baz(); // ok! 

E 'anche un'interfaccia più pulita e consente l'uso di SFINAE:

template<typename T> 
typename T::reference second(T::reference& t) { return t.at(1); }; 

template<typename T> 
T& second(T& t) { return t[1]; }; 

std::vector v(10); 
foo f(10); // type with [] overloaded but no reference typedef 
second(x) = 5; // calls first def 
second(f) = 3; // calls second def 
+1

Scusa ma penso che ti sia sfuggita la domanda. Stavo chiedendo quali operatori/caratteristiche il tipo 'reference' deve supportare ... non so se posso sovraccaricare o meno quello che c'è ... so già come funziona' typedef' e perché hanno introdotto l'astrazione, ecc .; Mi piacerebbe solo sapere cosa deve soddisfare un 'reference' secondo lo standard. – Mehrdad

+0

@Mehrdad 'reference' può fare tutto' value_type & 'può fare quale è tutto ciò che' value_type' può fare. – Pubby

+1

Quindi qual è il punto di usare 'reference' quando puoi usare' value_type & ', se sono la stessa cosa? Là * deve * essere un insieme di condizioni necessarie e sufficienti che 'il riferimento deve soddisfare, che è certamente * non *" tutto "... – Mehrdad

4

Credo che parte del problema deriva da un presupposto che ripartitori sono utili. Allocators (almeno pre-C++ 11) were something of a late addition to the STL:

La gente voleva contenitori indipendenti dal modello di memoria, che era un po 'eccessivo, perché la lingua non include modelli di memoria. Le persone volevano che la libreria fornisse un meccanismo per l'astrazione dei modelli di memoria. Le versioni precedenti di STL presupponevano che la dimensione del contenitore sia espressa come un numero intero di tipo size_t e che la distanza tra due iteratori sia di tipo ptrdiff_t. E ora ci è stato detto, perché non ti astraggo da questo? È un ordine alto perché la lingua non si distingue da quella; Gli array C e C++ non sono parametrizzati da questi tipi. Abbiamo inventato un meccanismo chiamato "allocatore", che incapsula informazioni sul modello di memoria. Ciò ha causato gravi conseguenze per ogni componente della biblioteca. Potresti chiederti quali modelli di memoria hanno a che fare con gli algoritmi o le interfacce del contenitore. Se non puoi usare cose come size_t, non puoi usare cose come T* a causa di diversi tipi di puntatori (T*, T huge *, ecc.). Quindi non è possibile utilizzare i riferimenti perché con diversi modelli di memoria si hanno diversi tipi di riferimento. C'erano enormi conseguenze sulla biblioteca.

Purtroppo, they turned out to be substandard:

ho inventato ripartitori a che fare con architettura di memoria di Intel. Non sono idee così cattive in teoria - avere uno strato che incapsula tutte le cose di memoria: puntatori, riferimenti, ptrdiff_t, size_t. Sfortunatamente non possono funzionare nella pratica. Ad esempio,

vector<int, alloc1> a(...); 
vector<int, alloc2> b(...); 

non si può dire ora:

find(a.begin(), a.end(), b[1]); 

b[1] restituisce un alloc2::reference e non int&. Potrebbe essere una mancata corrispondenza di tipo. È necessario cambiare il modo in cui il linguaggio principale gestisce i riferimenti per rendere davvero utili gli allocatori.

Il reference typedef è destinato a tornare qualunque sia l'equivalente di T& è per l'allocatore in questione. Sulle architetture moderne, questo è probabilmente T&. Tuttavia, l'ipotesi era che su alcune architetture potesse essere qualcosa di diverso (ad esempio, un compilatore che puntava su un'architettura con puntatori "vicini" e "lontani" potrebbe richiedere una sintassi speciale per i riferimenti "vicini" e "lontani"). Purtroppo, questa brillante idea si è rivelata meno brillante. C++ 11 apporta modifiche sostanziali agli allocatori - aggiungendo gli allocatori con scope - e il modello di memoria. Devo ammettere che non ne so abbastanza delle modifiche di C++ 11 w.r.t. allocatori per dire se le cose migliorano o peggiorano.


Guardando le osservazioni sulla domanda iniziale, dal momento che la standard in realtà non precisa in che modo i contenitori devono essere attuate (anche se la norma non ha messo così tanti requisiti sul comportamento dei contenitori che potrebbe pure. ..), qualunque sia il tipo che si digita come reference deve avere il comportamento di T& su cui qualcuno potrebbe potenzialmente fare affidamento quando si implementa il contenitore: un oggetto di tipo reference dovrebbe essere un alias trasparente dell'oggetto originale, assegnandogli dovrebbe cambiare il valore di l'oggetto originale senza affettare, non è necessario supportare "reinserire" lo reference, prendendo l'indirizzo dello reference dovrebbe restituire l'indirizzo della o oggetto originale, ecc. Se possibile, dovrebbe essere in realtà T&; e l'unico caso che posso immaginare dove non sarebbe possibile sarebbe se steste allocando memoria che non si possa manipolare tramite puntatori o riferimenti (ad esempio, se la "memoria" fosse effettivamente su disco, o se la memoria fosse effettivamente assegnato su un computer separato e raggiungibile tramite la rete tramite chiamate RPC, ecc.).

+0

Questo sembra essere per STL, non per STD. – Pubby

+1

"l'unico caso che posso immaginare dove non sarebbe possibile sarebbe se stavi allocando memoria che non puoi manipolare tramite puntatori o riferimenti" Lo standard non ti permetterebbe di creare allocatori con quello comunque, perché non puoi fingere un riferimento in C++. Non puoi dare una semantica di riferimento a un oggetto. Ecco perché 'vector ' non è tecnicamente un contenitore standard. Non segue le regole stabilite per le istanze di 'std :: vector'. E non perché devi essere in grado di fare '& vec [3]', il che è impossibile con 'vector '. –

+0

@Pubby: il codice STL esisteva prima dello standard ed è stato modificato in modo significativo quando è diventato parte dello standard (un cambiamento è dato dal fatto che i 2/3 degli algoritmi originariamente creati da Stepanov sono stati rimossi). Secondo Stepanov, il C++ è stato modificato in alcuni modi quando lo STL è stato adottato nello standard (un cambiamento è l'aggiunta di funtori). I miei commenti nell'ultimo paragrafo della risposta sono, credo, solo "corretti" per C++ - 98. C++ - 03 ha cambiato le regole in modo tale che le implementazioni sono autorizzate ad assumere che 'reference' è, in effetti,' T & '(come la tua risposta afferma, abbastanza chiaramente). –

2

Preso fuori norma:

enter image description here

Definisce anche reference come un typedef di value_type& che è un typedef di T

(risposta New come quello precedente era diversa messa a fuoco)

Problemi correlati