Perché il riferimento al valore 0x C ++ non è il valore predefinito?
Domanda
Una delle nuove fantastiche funzionalità del prossimo standard C ++, C ++ 0x, sono " riferimenti di valore. " Un riferimento al valore è simile a un riferimento al valore (normale), tranne per il fatto che può essere associato a un valore temporaneo (normalmente, un temporaneo può essere associato solo a un const
riferimento):
void FunctionWithLValueRef(int& a) {...}
void FunctionWithRValueRef(int&& a) {...}
int main() {
FunctionWithLValueRef(5); // error, 5 is a temporary
FunctionWithRValueRef(5); // okay
}
Quindi, perché hanno inventato un tipo completamente nuovo, anziché semplicemente rimuovere le restrizioni sui normali riferimenti per consentire loro di essere vincolati ai provvisori?
Soluzione
Sarebbe inutile. Cambieresti la cosa nella funzione e la modifica andrebbe persa immediatamente perché la cosa era in realtà temporanea.
Il motivo del nuovo tipo deriva dalla necessità di essere in grado di decidere cosa sia effettivamente un valore e cosa no. Solo così puoi effettivamente usarli per le cose interessanti che vengono utilizzate.
string toupper(string && s) { // for nonconst rvalues
for(char &c : s) make_uppercase(c);
return move(s); // move s into a returned string object
}
string toupper(string const& s) { // for the rest
// calls the rvalue reference version, by passing
// an rvalue copy.
return toupper(string(s));
}
Ora, se hai del valore e lo passi al toupper, il valore può essere modificato direttamente, perché sappiamo che il temporaneo è comunque una cosa da buttare via, quindi possiamo anche cambiarlo e non è necessario copiarlo esso. Inoltre, la stessa osservazione viene utilizzata per la cosa chiamata costruttori di mosse e assegnazione di mosse. Il lato destro non viene copiato, ma le sue cose vengono semplicemente rubate e spostate in *this
.
Se dovessi dire che i valori possono legarsi a riferimenti a valori non costanti, non avresti modo di capire se alla fine fa riferimento a un valore (oggetto denominato) o un valore (temporaneo).
Probabilmente è poco più noto, ma comunque utile, puoi mettere i riqualificatori di valore lvalue o rvalue su una funzione membro. Ecco un esempio, che estende naturalmente la semantica esistente dei riferimenti rvalue al parametro oggetto implicito:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
Ora, non puoi più dire
string() = "hello";
Il che è confuso e non ha davvero senso per la maggior parte del tempo. Ciò che &
sopra fa è che l'operatore di assegnazione può essere invocato solo su valori. Lo stesso può essere fatto per i valori, inserendo &&
.
Altri suggerimenti
Perché l'aggiunta di un nuovo tipo di riferimento consente di scrivere due overload di un metodo:
void CopyFrom(MyClass &&c)
{
dataMember.swap(c);
}
void CopyFrom(const MyClass &c)
{
dataMember.copyTheHardWay(c);
}
La versione che accetta il nuovo tipo di riferimento è autorizzata a modificare la variabile che riceve, poiché quella variabile non verrà utilizzata da nessun'altra parte. Quindi può & Quot; rubare & Quot; il suo contenuto.
Questo è il motivo per cui questa funzione è stata aggiunta; il mantenimento di un tipo di riferimento non raggiungerebbe l'obiettivo desiderato.