RVO (Ottimizzazione del valore di ritorno) su oggetti senza nome è un comportamento universalmente garantito?

StackOverflow https://stackoverflow.com/questions/8410877

Domanda

Questa domanda è in un aspetto diverso (anche limitato a GCC). La mia domanda è intesa solo per oggetti senza nome. Restituire l'ottimizzazione del valore è consentito cambiare il comportamento osservabile del programma risultante. Questo sembra essere menzionato anche in standard.

Tuttavia, questo "autorizzato a" il termine è confuso. Significa che RVO è garantito per accadere su ogni compilatore. A causa di RVO di seguito il codice modifica il suo comportamento osservabile:

#include<iostream>
int global = 0;
struct A {
  A(int *p) {}
  A(const A &obj) { ++ global; }
};

A foo () {  return A(0); }  // <--- RVO happens
int main () {
  A obj = foo(); 
  std::cout<<"global = "<<global<<"\n"; // prints 0 instead of 2
}

Questo programma supponiamo di stampare global = 0 Per tutte le implementazioni indipendentemente dalle ottimizzazioni del compilatore e dalla dimensione del metodo di foo ?

È stato utile?

Soluzione

Secondo lo standard, il programma può stampare 0, 1 o 2. Il paragrafo specifico in C ++ 11 è 12.8P31 che inizia con:

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

Si noti che entrambe le elvisioni di copia non sono un'ottimizzazione che cade nel come se regola (che richiede che il comportamento del programma sia coerente con il comportamento dello stesso programma come se Non si era verificata alcuna ottimizzazione). Lo standard consente esplicitamente l'implementazione di generare comportamenti osservabili diversi e dipende dal programmatore che il programma non dipenda da questo (o accettare tutti e tre i possibili risultati).

Nota 2: 1 non è menzionato in nessuna delle risposte, ma è un possibile risultato. Ci sono due potenziali copie che si svolgono, dalla variabile locale nella funzione all'oggetto restituito all'oggetto in main, il compilatore non può eliminare nessuna, una o le due copie che generano tutte e tre le possibili uscite.

Altri suggerimenti

Non può essere garantito. Se hai provato a scrivere una tale garanzia in modo coerente, troverai impossibile farlo.

Ad esempio, considera questo codice:

std::string f() {
  std::string first("first");
  std::string second("second");
  return FunctionThatIsAlwaysFalse() ? first : second;
}

La funzione FunctionThatIsAlwaysFalse ritorna sempre false, ma puoi dirlo solo se esegui ottimizzazioni inter-moduli. Lo standard dovrebbe richiedere a ogni singolo compilatore di eseguire l'ottimizzazione inter-modulo in modo da poter utilizzare RVO in questo caso? Come funzionerebbe? O dovrebbe vietare a qualsiasi compilatore di utilizzare RVO quando sono necessarie ottimizzazioni inter-moduli? Come funzionerebbe? Come può fermare i compilatori abbastanza intelligenti da vedere che RVO è possibile farlo e quelli che non sono dal non farlo?

L'elenco standard dovrebbe essere richiesto ogni compilatori di ottimizzazione per supportare con RVO? E dovrebbe proibire RVO in altri casi? Questo tipo di sconfiggere il punto di ottimizzare i compilatori?

E i casi in cui il compilatore crede che RVO ridurrà le prestazioni? Il compilatore dovrebbe essere tenuto a fare un'ottimizzazione che ritiene cattiva? Per esempio:

if(FunctionCompilerKnowsHasNoSideEffectsAndThinksMostlyReturnsFalse())
  return F(3); // Here RVO is a pessimization
else
{
 Foo j=F(3);
 return Foo(j);
}

Qui, se il compilatore non è tenuto a fare RTO, se può evitare il if E la funzione chiamata, poiché senza RTO, il codice è lo stesso in entrambe le metà. Dovresti forzare il compilatore a fare un'ottimizzazione che pensa peggiora le cose? Come mai?

Non c'è davvero modo di far funzionare una tale garanzia.

Pedanticamente parlando la sua implementazione definita. I compilatori moderni sono abbastanza intelligenti da fare questo tipo di ottimizzazione.

Ma non vi è alcuna garanzia che il comportamento sarebbe esattamente lo stesso tra le implementazioni. Questo è ciò che implementazione definita Il comportamento riguarda tutto.

"permesso" in questo contesto significa che 0 o 1 o 2 sono output di conformità standard.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top