2012-12-26 9 views
7

Una funzione deve restituire due valori al chiamante. Qual è il modo migliore per implementare?RVO si verifica quando si restituisce std :: pair?

Opzione 1:

pair<U,V> myfunc() 
{ 
... 
return make_pair(getU(),getV()); 
} 

pair<U,V> mypair = myfunc(); 

Opzione 1.1:

// Same defn 
U u; V v; 
tie(u,v) = myfunc(); 

Opzione 2:

void myfunc(U& u , V& v) 
{ 
u = getU(); v= getV(); 
} 

U u; V v; 
myfunc(u,v); 

so che con Option2, non ci sono copie/si muove ma sembra brutto. Ci saranno copie/mosse in Option1, 1.1? Supponiamo che U e V siano oggetti enormi che supportano entrambe le operazioni di copia/spostamento.

Q: È teoricamente possibile per qualsiasi ottimizzazione RVO/NRVO secondo lo standard? Se sì, gcc o qualsiasi altro compilatore è già implementato?

+1

Non so nulla di 'std :: pair' che inibisce RVO/NRVO. È generalmente abbastanza facile da testare includendo un costruttore di copie che ti dice quando avviene una copia. –

+1

g ++ implementa RVO che impedisce di copiare la coppia, tuttavia si ha ancora la copia di uev nella coppia. –

+0

Ho eseguito alcuni test e ho scoperto che con g ++, quale era più veloce dipendeva molto da cosa fosse possibile l'inlining e la complessità dei costruttori di copie per U e V. Se stai cercando prestazioni, penso che devi profilare per determinare quale è il più veloce. –

risposta

8

RVO si verifica quando si restituisce std::pair?

Sì, è possibile.

È garantito che si verifichi?

No, non lo è.


C++ 11 norma: Sezione 12.8/31:

Quando determinati criteri sono soddisfatti, un'implementazione è consentito omettere la copia costruzione/spostamento di un oggetto classe, anche se il costruttore di copia/movimento e/o il distruttore per l'oggetto hanno effetti collaterali.

Copia elision non è una funzione garantita. È possibile che i compilatori di ottimizzazione eseguano ogni volta che riescono a. Non c'è niente di speciale nel numero std::pair. Se un compilatore è abbastanza buono da rilevare un'opportunità di ottimizzazione lo farà. Quindi la tua domanda è specifica del compilatore ma si applica la stessa regola allo std::pair come a qualsiasi altra classe.

1

RVO o Copia elision dipende dal compilatore, quindi se si desidera avere RVO ed evitare la chiamata a Copia l'opzione migliore del costruttore è quella di utilizzare i puntatori.

Nel nostro prodotto utilizziamo puntatori e incrementa il puntatore dei contenitori per evitare il costruttore di copia. e questo offre un incremento delle prestazioni di circa il 10%.

Venendo alla tua domanda, Nell'opzione 1 U e V copia costruttore non sarà chiamato come non stai restituendo U o V, ma restituendo std :: coppia oggetto in modo che sarà chiamato costruttore di copia e la maggior parte dei compilatori utilizzerà definitivamente RVO qui per evitarlo.

Grazie Niraj Rathi

4

Mentre RVO non è garantita, in C++ 11 la funzione come è stato definito Credo deve muoversi ritorno per lo meno, quindi vorrei suggerire di lasciare la definizione più chiara piuttosto di deformarlo per accettare variabili di output (a meno che tu non abbia una politica specifica per utilizzarle).

Inoltre, anche se questo esempio ha utilizzato RVO, l'uso esplicito di make_pair significa che si avrà sempre almeno una costruzione di coppia aggiuntiva e quindi un'operazione di spostamento. Cambiarlo per restituire un'espressione inizializzata controventata:

return { getU(), getV() }; 
Problemi correlati