2012-12-23 13 views
11

Eventuali duplicati:
What happens if I return literal instead of declared std::string?comprensione C++ 11 rvalues, muovono la semantica e le prestazioni

Si consideri il seguente codice

1| string getName() { 
2|  return "meme"; 
3| } 
4| 
5| string name = getName(); 

La funzione getName() restituisce un oggetto temporaneo. In C++ 03, capisco che il costruttore di copia di "string" viene chiamato e l'oggetto temporaneo viene distrutto. In realtà sembra che il compilatore (almeno in gcc 4.7) ottimizzi la linea 5 non creando l'oggetto "nome" ma sostituendolo con l'oggetto temporaneo stesso e non distruggendo l'oggetto temporaneo (ho provato con una classe MyVector, non con std :: string).

Come definito negli standard C++ 11,
1. getName() restituisce un valore?
2. Nella riga 5 sopra, quale costruttore di stringa viene chiamato (sposta o copia)? Devo necessariamente chiamare std :: move() per chiamare il costruttore di movimento?
3. Con la semantica del movimento, è meno efficiente dell'ottimizzazione "copia elision" fornita dal compilatore?

+2

Sarebbe _copy elision _... –

+0

@ K-ballo grazie per avermi illuminato. –

+0

L'aggiunta di numeri di linea è straordinaria! Mai visto prima =) – qwertz

risposta

18
  1. funzioni non ritorno rvalues ​​o lvalue. Le categorie di valore si applicano alle espressioni. Quindi un'espressione che chiama una funzione può essere un valore o un valore. In questo caso, l'espressione getName() è un'espressione rvalue poiché la funzione getName restituisce un oggetto per valore. Questo deriva dal §5.2.2/10:

    Una chiamata di funzione è un lvalue se il tipo risultato è un tipo di riferimento lvalue o un riferimento rvalue operato tipo, un xValue se il tipo di risultato è un riferimento a rvalue tipo di oggetto e un valore di prerequisito,.

    Il tipo di risultato delle funzioni non è un riferimento di lvalue o di rvalue, pertanto la chiamata di funzione è un valore di prvalore. le espressioni di valore sono un sottoinsieme di espressioni rvalue.

  2. Il costruttore di movimento verrà utilizzato (a meno che non sia elidato, quale potrebbe essere). Questo perché getName() è un valore rvalore, quindi il costruttore di std::string che accetta un riferimento rvalue corrisponderà meglio all'argomento. Si noti che anche se la costruzione del movimento viene eliminata, il costruttore di movimento deve essere ancora accessibile. Cioè, il codice deve essere compilabile anche se non è elidato.

  3. In generale, l'ottimizzazione di copia o spostamento elision si eliminerà completamente da qualsiasi copia o spostamento. Quindi, ovviamente, è più veloce di fare una mossa. Se una mossa viene eliminata, letteralmente non succede nulla. Non ci sarà codice emesso per quella mossa. Il compilatore raggiunge questo costruendo direttamente l'oggetto nella posizione in cui verrebbe copiato o spostato.

Vale la pena ricordare che questo potrebbe anche essere equivalentemente ottimizzato:

string getName() { 
    std::string str("meme"); 
    return str; 
} 

string name = getName(); 

Qui, due movimenti sarà tralasciata (coinvolgendo ciò che è comunemente noto come Named Return Value Optimization). Ci sono due punti da considerare qui. In primo luogo, return str; soddisfa i criteri di copia/spostamento elision (§12.8/31):

Questa elisione delle operazioni di copia/spostamento, chiamato copia elisione, è consentito nei seguenti casi (che possono essere combinati per eliminare le copie multiple):

  • in una dichiarazione di ritorno in funzione con un tipo di classe di ritorno, quando l'espressione è il nome di un oggetto automatico non volatile (diverso da una funzione o parametro di catch-clausola) con il stesso tipo cv-non qualificato come tipo restituito dalla funzione, l'operazione di copia/spostamento può essere omessa costruendo direttamente l'oggetto automatico int o il valore restituito dalla funzione
  • ...

seconda è che, anche se str è un lvalue, sarà ancora spostato da quanto si inseriscono un caso particolare in standard (§12.8/32):

Quando i criteri per l'elisione di un'operazione di copia sono soddisfatti o verrebbero soddisfatti salvo il fatto che l'oggetto di origine è un parametro di funzione e l'oggetto da copiare è designato da un lvalue, risoluzione di sovraccarico selezionare il costruttore per la copia viene prima eseguita come se l'oggetto fosse designato b y un valore.

Problemi correlati