Per il tuo caso particolare, il secondo sovraccarico è inutile.
Con il codice originale, che ha un solo sovraccarico per Load
, questa funzione viene chiamata per lvalue e valori.
Con il nuovo codice, il primo overload viene chiamato per lvalue e il secondo viene chiamato per valori rvalue. Tuttavia, il secondo sovraccarico chiama il primo. Alla fine, l'effetto di chiamare uno o l'altro implica che verrà eseguita la stessa operazione (qualunque sia il primo sovraccarico).
Pertanto, gli effetti del codice originale e del nuovo codice sono gli stessi, ma il primo codice è più semplice.
Decidere se una funzione deve prendere un argomento per valore, il riferimento di lvalue o il riferimento di valore dipende molto da ciò che fa. È necessario fornire un sovraccarico prendendo i riferimenti di valore quando si desidera spostare l'argomento passato. Ci sono molti buoni references in movimento semantincs là fuori, quindi non lo copro qui.
Bonus:
per aiutarmi a fare il mio punto di prendere in considerazione questo semplice probe
classe:
struct probe {
probe(const char* ) { std::cout << "ctr " << std::endl; }
probe(const probe&) { std::cout << "copy" << std::endl; }
probe(probe&& ) { std::cout << "move" << std::endl; }
};
Ora considerare questa funzione:
void f(const probe& p) {
probe q(p);
// use q;
}
Calling f("foo");
produce il seguente output:
ctr
copy
Nessuna sorpresa qui: creiamo un probe
temporaneo passando il const char*
"foo"
. Da qui la prima linea di uscita. Quindi, questo temporaneo è associato a p
e una copia q
di p
viene creata all'interno di f
. Da qui la seconda linea di uscita.
Ora, in considerazione di prendere p
per valore, cioè, modificare f
a:
void f(probe p) {
// use p;
}
L'uscita del f("foo");
è ora
ctr
Alcuni saranno sorpresi che in questo caso: non c'è copia! In generale, se prendi un argomento per riferimento e lo copi all'interno della tua funzione, allora è meglio prendere l'argomento per valore. In questo caso, invece di creare una copia temporanea e copiarla, il compilatore può costruire l'argomento (p
in questo caso) direttamente dall'input ("foo"
). Per ulteriori informazioni, vedere Want Speed? Pass by Value. di Dave Abrahams.
Ci sono due eccezioni notevoli a questa linea guida: costruttori e operatori di assegnazione.
Considerate questa classe:
struct foo {
probe p;
foo(const probe& q) : p(q) { }
};
Il costruttore prende un probe
per riferimento const e quindi copiarlo p
. In questo caso, seguire le linee guida sopra riportate non porta alcun miglioramento delle prestazioni e il costruttore di copie di probe
verrà chiamato comunque. Tuttavia, assumere il valore q
in base al valore potrebbe creare un problema di risoluzione di sovraccarico simile a quello con l'operatore di assegnazione che coprirò ora.
Supponiamo che la nostra classe probe
abbia un metodo di non lancio swap
. Poi l'attuazione suggerito del suo operatore di assegnazione (Pensare in C++ 03 termini per il momento) è
probe& operator =(const probe& other) {
probe tmp(other);
swap(tmp);
return *this;
}
Poi, secondo le linee guida di cui sopra, è meglio scrivere in questo modo
probe& operator =(probe tmp) {
swap(tmp);
return *this;
}
Ora immettere C++ 11 con riferimenti rvalue e spostare la semantica. Hai deciso di aggiungere un operatore di assegnamento mossa:
probe& operator =(probe&&);
Ora chiamando l'operatore di assegnazione a titolo temporaneo crea un'ambiguità perché entrambi i sovraccarichi sono vitali e nessuno è preferito rispetto all'altro. Per risolvere questo problema, utilizzare l'implementazione originale dell'operatore di assegnazione (prendendo l'argomento con riferimento const).
In realtà, questo problema non è specifico per i costruttori e gli operatori di assegnazione e potrebbe accadere con qualsiasi funzione. (E 'più probabile che si verificherà con costruttori e operatori di assegnazione però.) Ad esempio, chiamando g("foo");
quando g
ha i seguenti due overload solleva l'ambiguità:
void g(probe);
void g(probe&&);
'Per risolvere questo problema, utilizzare l'implementazione originale dell'operatore di assegnazione (prendendo l'argomento con riferimento const) .' Invece basta applicare il common copy-and-swap-idiom implementando un costruttore di mosse e lasciando che il compilatore decida di copiare - o move- costruisce la variabile 'tmp' per l'operatore di assegnazione. – SebNag