2009-07-14 12 views
9

Diversamente da std :: map e std :: hash_map, le versioni corrispondenti in Qt non si preoccupano di restituire un riferimento. Non è abbastanza inefficiente, se costruisco un hash per classi abbastanza ingombranti?Qualche idea per cui QHash e QMap restituiscono const T invece di const T &?

EDIT

soprattutto perché c'è un valore metodo separato(), che potrebbe poi riportarlo al valore.

+0

Eventuali duplicati di [Perché QMap :: operator [\] (const Key & chiave) di ritorno per valore \ ?] (https://stackoverflow.com/questions/18503700/why-does-qmapoperatorconst-key-key-return-by-value) –

+0

@ThomasCerto sicuro, appena chiesto 5 anni prima – MadH

risposta

29

Gli operatori di pedici cost di STL contenitori possono restituire un riferimento-a-const perché rifiutano le chiamate ad esso con indici che non esistono nel contenitore. Il comportamento in questo caso non è definito. Di conseguenza, come una scelta di design saggia, std::map non fornisce nemmeno un sovraccarico dell'operatore di sottoscrizione const.

QMap tenta di essere un po 'più accomodante, fornisce un sovraccarico dell'operatore di pedice const come zucchero sintattico, si imbatte nel problema con le chiavi non esistenti, tenta nuovamente di essere più accomodante e restituisce invece un valore predefinito.

Se si desidera mantenere la convenzione return-by-const-reference di STL, è necessario allocare un valore statico e restituire un riferimento a a. Ciò, tuttavia, sarebbe abbastanza in disaccordo con le garanzie di rientranza fornite da QMap, quindi l'unica opzione è quella di restituire per valore. Il const c'è solo un rivestimento di zucchero per prevenire alcuni errori stupidi come constmap["foo"]++ dalla compilazione.

Detto questo, il ritorno tramite riferimento non è sempre il modo più efficiente. Se restituisci un tipo fondamentale o, con ottimizzazione più aggressiva, quando sizeof(T)<=sizeof(void*), return-by-value spesso fa in modo che il compilatore restituisca il risultato in un registro direttamente anziché indirettamente (indirizzo per generare il registro) o-heaven forbid-on pila.

L'altro motivo (oltre alla premessa pessimizzazione) per preferire il riferimento pass-by-cost, l'affettatura, non si applica qui, poiché entrambi std::map e QMap sono basati sul valore e quindi omogenei.Per un contenitore eterogeneo, devi tenere puntatori e i puntatori sono tipi fondamentali (eccetto quelli intelligenti, ovviamente).

Ciò detto, non utilizzo quasi mai l'operatore const subscript in Qt. Sì, ha una sintassi più gradevole di find() + *it, ma invariabilmente finirai con le chiamate count()/ proprio di fronte all'operatore const subscript, il che significa che stai facendo la ricerca binaria due volte. E poi non noterete le differenze in termini di prestazioni minuscole valore di ritorno comunque :)

Per value() const, però, sono d'accordo che deve restituire riferimento a const, inadempiente al riferimento-to-default-value essere passato come secondo argomento, ma suppongo che gli sviluppatori di Qt sentissero che era troppo magico.

+0

"std :: map const subscript operator ..." Ma 'std :: map' non ha un operatore di pedice' const'? –

+0

Abbastanza corretto, modificato. Minori dettagli, però :) –

+0

"negano le chiamate con indici che non esistono nel contenitore", ma puoi farlo su std :: map, è un modo per inserire nuovi valori. Ma anche se intendevi nel caso generale, come segue che non forniscono un operatore const subscript? – CiscoIPPhone

1

Strano, sì.

Forse questo è a causa della semantica desiderata, dove si fa ad es. value() su una chiave non specificata, restituisce un valore predefinito costruito del tipo corretto. Non è possibile utilizzare riferimenti, almeno non in modo pulito.

Inoltre, cose come name return value optimization possono ridurre l'impatto sulle prestazioni di questo progetto.

3

In realtà, alcuni dei metodi fare restituire un riferimento ... per esempio, la versione non-const di operator[] restituisce un T &.

Tuttavia, la versione const di operator[] restituisce un const T. Perché? Come già notato, "unwind", la ragione ha a che fare con ciò che accade quando la chiave non esiste nella mappa. Nel non-const operator[], possiamo aggiungere la chiave alla mappa, quindi restituire un riferimento alla voce appena aggiunta. Tuttavia, il const operator[] non può farlo perché non può modificare la mappa. Allora, a cosa dovrebbe restituire un riferimento? La soluzione consiste nel rendere const Tconst T e restituire uno T predefinito nel caso in cui la chiave non sia presente nella mappa.

+1

Preferirei avere un comportamento da operatore [] lo stesso del metodo std :: e value() per restituirlo per valore ... – MadH

+0

Ok, ma perché non 'const T QHash :: value (const Key & key, const T e defaultValue) const' restituisce un riferimento ? –

4

La documentazione per QMap e QHash specifica specificamente per evitare operator[] per la ricerca a causa del motivo indicato da Martin B.

Se si desidera un riferimento const, utilizzare const_iterator find (const Key & key) const dove è possibile quindi utilizzare uno dei:

const Key & key() const 
const T & value() const 
const T & operator*() const 
const T * operator->() const 
Problemi correlati