2014-07-18 19 views
18

Sto scavando un po 'le qualifiche di ref, seguendo una domanda precedente.Qual è l'uso del qualificatore ref `const &&`?

Dato il codice di esempio riportato di seguito;

#include <iostream> 
#include <string> 
#include <utility> 

struct A { 
    std::string abc = "abc"; 
    std::string& get() & { 
    std::cout << "get() &" << std::endl; 
    return abc; 
    } 
    std::string get() && { 
    std::cout << "get() &&" << std::endl; 
    return std::move(abc); 
    } 
    std::string const& get() const & { 
    std::cout << "get() const &" << std::endl; 
    return abc; 
    } 
    std::string get() const && { 
    std::cout << "get() const &&" << std::endl; 
    return abc; 
    } 
}; 

int main() 
{ 
    A a1; 
    a1.get(); 
    const A a2{}; 
    a2.get(); 
    A().get(); 
    const A a3{}; 
    std::move(a3).get(); 
} 

e l'uscita è come ci si aspetterebbe:

get() &
get() const &
get() & &
get() const & &

Questo compila ed esegue con clang e gcc 4.9.1 (non con 4.9.0). Dal vivo sample here.

In codice generale (il campione è lì per vedere come il codice viene compilato ed eseguito).

  • Quale sarebbe lo scopo della const && ref-qualificazione su un metodo essere?

Il metodo è in grado di modificare il contenuto sull'oggetto (è const), un tentativo di return std::move(abc); dal metodo const && realtà non spostare il std::string affatto. Presumibilmente vorresti essere in grado di modificare l'oggetto, poiché è un valore r e non sarà disponibile per molto tempo. Se fosse necessario rimuovere il metodo qualificato const &&, il codice std::move(a3).method() si collegherebbe al metodo qualificato const &, il che avrebbe senso.

  • cosa, se del caso, sarebbe la differenza semantica implicita essere compreso tra un metodo qualificato come const & e uno qualificato come const &&? Cioè come cambierebbe l'implementazione o perché vorresti entrambi?
  • Il std::string potrebbe essere "spostato" fuori dall'oggetto temporaneo?
  • Che aspetto avrebbe una firma "canonica" per std::string get() const && in questo caso?

risposta

10

Sull'utilità di const&& ... (in generale)

L'utilità del qualificatore const&& nel metodo membro è minima nella migliore delle ipotesi. L'oggetto non può essere modificato nello stesso modo in cui un metodo && consente di modificarlo; dopo tutto è const (come notato, lo mutable lo cambia). Quindi non saremo in grado di strappare il suo coraggio, poiché il temporaneo sta scadendo comunque, come faremmo in qualcosa di simile a un normale move.

In molti modi l'utilità del const&& può essere meglio valutato nel contesto di quanto sia utile un oggetto di tipo const T&& è per cominciare. Quanto è utile l'argomento di una funzione? Come indicato in un'altra risposta (a questa domanda) here, sono molto utili nel dichiarare funzioni cancellate, ad es. in questo caso

template <class T> void ref (const T&&) = delete; 

per disabilitare esplicitamente oggetti di tipi e categorie prvalue valore xValue venga utilizzato con le funzioni, e const T&& fa bind to all prvalue and xvalue objects.

Qual è l'utilità del qualificatore di metodo const&&?

E 'interessante notare che nella proposta C++ library extensions, optional, § 5.3, include sovraccarichi, per esempio

constexpr T value() const &&; 

che sono qualificati come const&& e specificati per eseguire la stessa azione del && alternativa.

Il motivo per cui posso dedurre per questo caso; è che questo è per completezza e correttezza. Se il metodo value() viene richiamato su un valore rvalue, esegue la stessa azione indipendentemente dal fatto che sia const o meno. Lo const dovrà essere gestito dall'oggetto contenuto che viene spostato o dal codice client che lo utilizza. Se esiste uno stato mutable con l'oggetto contenuto, allora quello stato può essere legittimamente modificato.

Potrebbe esserci ancora qualche merito in questo; in ordine sparso ...

  • di dichiararla = delete di vietare l'uso del metodo su prvalues ​​e XValues.
  • Se il tipo ha stato mutabile e il qualificatore ha senso (possibilmente in aggiunta agli altri qualificatori) nell'ambiente di destinazione, considerarlo.
  • Se si implementa un tipo di contenitore generico, quindi per completezza e correttezza , considerare di aggiungerlo ed eseguire la stessa azione del metodo &&. I consigli qui sono ordinati dalla libreria standard (e dalle sue estensioni).

Cosa sarebbe una firma "canonica" apparire come un metodo qualificato const&&?

Dato che il metodo sarà eseguire la stessa azione del metodo di &&, Auspico, pertanto, che la firma corrisponda alla firma &&.

+0

"Se stai implementando un tipo di contenitore generico, quindi per completezza e correttezza, considera di aggiungerlo ed eseguire la stessa azione del metodo &&. " - Non puoi, perché il contenitore e il suo contenuto devono essere trattati come 'const'. Il metodo 'const &' qualificato verrà chiamato invece per 'const' rvalue object access. – Potatoswatter

+0

@Potatoswatter. Che è come è specificato nelle estensioni della libreria C++ per 'optional' et. al. I metodi '&&' e 'const &&' hanno lo stesso effetto (n4082, sezione 5.3.5 para 11, 20 ecc.). Vale la pena notare che GCC ha un problema nel selezionare il metodo corretto dato un valore const, ma clang no.Penso che il punto qui sia che, in generale, non c'è alcun uso, ma ci sono alcuni casi angolari che potrebbero essere necessari (e poi considerare attentamente perché ne hai bisogno). – Niall

2

Vedo due utilizzi principali per qualificare un metodo. Uno è come mostrato nel tuo metodo get() &&, dove lo usi per selezionare un'implementazione potenzialmente più efficiente che è disponibile solo quando sai che l'oggetto non sarà più utilizzato. Ma l'altro è un suggerimento di sicurezza per evitare di chiamare determinati metodi su oggetti temporanei.

In questi casi è possibile utilizzare la notazione come get() const && = delete, anche se realisticamente salverei questo approccio per la modifica dei metodi, in particolare quelli che sono potenzialmente costosi. Non ha molto senso mutare e quindi scartare un oggetto senza recuperare qualcosa, e doppiamente se è costoso eseguire la mutazione. Questo costrutto fornisce al compilatore un modo per contrassegnare e impedire tale utilizzo.

+0

Il '= delete' ti dà un sacco di controllo su come l'oggetto non può essere utilizzato, penso che questo sarebbe' const && 'uso generale (se non del tutto). – Niall

9

possiamo trovare una simile esplorazione di questo problema in questo articolo What are const rvalue references good for? e quello dell'uso che si è distinto sia questo esempio forma la libreria standard:

template <class T> void ref (const T&&) = delete; 
template <class T> void cref (const T&&) = delete; 

che disabilita ref e cref per rvalues ​​del tutto. Possiamo trovare queste dichiarazioni nella sezione draft C++11 standard20.8Oggetti funzionali paragrafo .

Scott Meyers allude a questo uso in Universal References in C++11:

Anche la semplice aggiunta di un qualificatore const è sufficiente per disattivare la interpretazione di “& &” come riferimento universale:

+0

Penso di essere d'accordo con l'articolo, in generale, specialmente con i metodi qualificati ref, c'è poco uso se non quello di vietare l'uso. – Niall

+0

Si noti che ci sono più domande pertinenti su SO che precedono quell'articolo. Ad esempio, http://stackoverflow.com/q/4938875/103167 –

+0

@BenVoigt ce ne sono alcuni, non sono andato oltre il mio primo hit di ricerca poiché ha risposto molto bene alla domanda e in realtà ha esplorato il problema in modo accurato un modo molto simile Questa domanda però è di gran lunga la migliore qualità. –

3

Supponiamo di avere un tipo con uno stato mutable. Quindi const&& ci consentiranno entrambi di mutare quello stato e indicano che tale mutazione è sicura.

struct bar; 

struct foo { 
    mutable std::vector<char> state; 
    operator bar() const&; 
    operator bar() const&&; 
}; 

const non è assoluto.

Blocco stato mutabile, non è sicuro per allontanare const in un metodo const&& per estrarre stato, poiché l'estrazione stato in tal modo da un oggetto reale const è comportamento indefinito.

+0

'mutable' porta qualcosa di molto interessante sul tavolo, perché dice anche qualcosa sulla sicurezza dei thread anche in C++ 11. – Niall

+0

@niall solo se in contenitori 'std'. O tipi forniti da 'std'. – Yakk

+0

Questo è un buon punto. Sono d'accordo, tecnicamente sì. Da un punto di vista personale, però, generalmente mi aspetto che i tipi siano utilizzabili con e dalla libreria standard. Dati gli attuali livelli di conformità riscontrati nelle implementazioni generali, penso che tutti potremmo o dovremmo - sarebbe contro-intuitivo se non fosse così. Penso che la libreria standard fornisca un modello ragionevolmente buono da seguire. Capisco anche il pensiero che questo non sarà sempre applicabile - ma penso che questi casi siano o debbano essere limitati (ne so alcuni). – Niall

Problemi correlati