2016-07-11 8 views
10

Consideriamo queste due funzioni:C++ di ottimizzazione valore di ritorno, più i rendimenti senza nome

// 1. Multiple returns of the same named object 
string f() { 
    string s; 
    if (something()) 
     return s.assign(get_value1()); 
    else 
     return s.assign(get_value2()); 
} 

e

// 2. Multiple returns, all of unnamed objects 
string g() { 
    if (something()) 
     return get_value1(); 
    else 
     return get_value2(); 
} 

Come ciascuna di queste funzioni sarà effettivamente si comportano in termini di RVO è naturalmente compilatore-dipendente . Ho ragione, tuttavia, presumere che il RVO per entrambi sia comune?


p.s. (vedi risposte) Funzione # 1 era destinato ad essere il seguente:

string f() { 
    string s; 
    if (something()) 
     return s; 
    s.assign(get_value()); 
    return s; 
} 

risposta

12

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_valuestring (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 return10 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.

+0

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. –

+0

@ 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

+0

Ripensandoci, penso che trasferirò questo commento nella risposta. – bogdan

Problemi correlati