per # 1, NRVO è garantito non accada, cioè, avrete la garanzia di ottenere una copia dal s
al valore di ritorno della funzione. In questo caso, è meglio fare
return std::move(s.assign(get_value1()));
In alternativa, se possibile, riscrivere la funzione di essere NRVO-friendly:
string f() {
string s;
if (something())
s.assign(get_value1());
else
s.assign(get_value2());
return s;
}
Prima che il compilatore considera anche NRVO, diversi requisiti standard devono essere soddisfatti. Quello che non è soddisfatto qui è che l'espressione nell'istruzione return
deve essere il nome di una variabile. s.assign(...)
non è un nome, è un'espressione più complicata; è necessario avere qualcosa come return s;
per NRVO da considerare.
Per 2 #, assumendo le funzioni restituiscono get_value
string
(o const string
), è molto probabile avere RVO su qualsiasi compilatore moderno, e, se tutto va bene con la ratifica del C++ 17, RVO sarà garantito in modalità C++ 17 in qualsiasi compilatore conforme (ancora nessuna garanzia per NRVO).
È possibile trovare informazioni molto buone e complete su (N) RVO (chiamate copia elision nello standard) su cppreference.com.
ho deciso di controllare lo stato del compilatore corrente, così ho fatto alcuni test su GCC 6.1.0, 3.8.0 e Clang MSVC 2015 Aggiornamento 3.
Per 2 #, si ottiene RVO da tutti e tre i compilatori (i prvalues nelle dichiarazioni return
10 sono abbastanza facili da analizzare).
Si ottiene inoltre NRVO da tutti e tre i compilatori per un costrutto come "NRVO-friendly" precedente (per MSVC, è necessario che le ottimizzazioni siano abilitate).
Tuttavia, per una funzione come
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}
GCC e Clang fare NRVO, ma MSVC non lo fa; tuttavia genera spostamenti da s
al valore di ritorno, che è conforme alla norma.
Per un altro esempio:
string f() {
string s;
if (something())
return get_value1();
if (something_else())
return get_value2();
s.assign(get_value3());
return s;
}
Tutti e tre compilatori RVO per i primi due return
s ed un passaggio dal s
per il terzo.
Grazie per la risposta. Ho concepito il 'get_value' come valutazione di' string'. E quando mi sono compenetrato, mi sono arrischiato, quello che intendevo per # 1 sarebbe stato in pratica più simile a "stringa s"; if (sthg()) {return s;} s.assign (get_value()); return s; '. Ancora un promemoria che "copia elision" non accadrà se sono negligente. Poiché la mia domanda è stata incentrata principalmente sul secondo caso, la contrassegnerò come risolta e non la modificherò ulteriormente. –
@ n.caillou Quel costrutto fa spuntare tutte le caselle per i requisiti standard per copia elision, e sembra che tu abbia NRVO da GCC e Clang, ma non da MSVC (2015 Update 3) - più dichiarazioni di reso con lo stesso nome di variabile ancora lo confondono. Tuttavia genera mosse da 's' al valore di ritorno, che è conforme alla norma. Se MSVC è importante nel tuo caso, probabilmente è meglio riscrivere la funzione per tornare in un posto per 'return s;'. Multiple 'return get_value();' vanno bene per tutti e tre i compilatori - i prvalue sono più facili da analizzare per il compilatore. – bogdan
Ripensandoci, penso che trasferirò questo commento nella risposta. – bogdan