Interessante. Penso che sia sicuro, per ragioni contorte. (Per la cronaca, ho anche lo considerano molto cattivo stile - una copia esplicito ti costa niente qui, dal momento che verrà spostato nella mappa.)
Prima di tutto, la chiamata di funzione reale non è un problema . std::move
esegue il cast di a
solo su un riferimento di rvalue e i riferimenti di rvalue sono solo riferimenti; a non viene immediatamente spostato. emplace_back
inoltra i suoi parametri a un costruttore di std::pair<std::string, A>
, ed è qui che le cose diventano interessanti.
Quindi, quale costruttore di std::pair
viene utilizzato? Ha piuttosto molti, ma due sono rilevanti:
pair(const T1& x, const T2& y);
template<class U, class V> pair(U&& x, U&&y);
(Vedi 20.3.2 nello standard), dove T1
e T2
sono gli argomenti di template di std::pair
. Come per 13.3, finiamo in quest'ultimo con U == const T1&
e V == T2
, il che ha un senso intuitivo (altrimenti muoversi in uno std::pair
sarebbe effettivamente impossibile). Questo ci lascia con un costruttore del modulo
pair(const T1& x, T2 &&y) : first(std::forward(x)), second(std::forward(y)) { }
come da 20.3.2 (6-8).
Quindi, è sicuro? In linea di massima, std::pair
è definito in dettaglio, incluso il layout della memoria. In particolare, si afferma che
T1 first;
T2 second;
sono disponibili in questo ordine, in modo first
verranno inizializzate prima second
. Ciò significa che nel tuo caso particolare, la stringa verrà copiata prima che venga spostata e tu sei al sicuro.
Tuttavia, se si stavano facendo il contrario:
m.emplace(std::move(A.s), A); // huh?
... poi si otterrebbe effetti divertenti.
@JoachimPileborg In questo caso, nessun oggetto 'A' si crea nella chiamata, in quanto' std :: mappa :: emplace' prende riferimenti universali. Se il secondo argomento fosse preso in base al valore, allora l'ordine di valutazione sarebbe importante. –
@DDrmmr Dopo aver letto alcuni riferimenti/specifiche/risposta Wintermutes, hai ragione. Questo dovrebbe essere sicuro. –