2011-06-17 29 views
10

Ho voluto verificare il se le seguenti ottimizzazioni funzionano come previsto:Condizioni per copia elisione?

  • RVO
  • Chiamato RVO
  • Copia elisione quando passa un argomento per valore

Così ho scritto questo piccolo programma :

#include <algorithm> 
#include <cstddef> 
#include <iostream> 
#include <vector> 

struct Foo { 
    Foo(std::size_t length, char value) : data(length, value) { } 

    Foo(const Foo & rhs) : data(rhs.data) { std::cout << "*** COPY ***" << std::endl; } 

    Foo & operator= (Foo rhs) { 
     std::cout << "*** ASSIGNMENT ***" << std::endl; 
     std::swap(data, rhs.data); // probably expensive, ignore this please 
     return *this; 
    } 

    ~Foo() { } 

    std::vector<char> data; 
}; 

Foo TestRVO() { return Foo(512, 'r'); } 

Foo TestNamedRVO() { Foo result(512, 'n'); return result; } 

void PassByValue(Foo inFoo) {} 

int main() 
{ 
    std::cout << "\nTest RVO: " << std::endl; 
    Foo rvo = TestRVO(); 

    std::cout << "\nTest named RVO: " << std::endl; 
    Foo named_rvo = TestNamedRVO(); 

    std::cout << "\nTest PassByValue: " << std::endl; 
    Foo foo(512, 'a'); 
    PassByValue(foo); 

    std::cout << "\nTest assignment: " << std::endl; 
    Foo f(512, 'f'); 
    Foo g(512, 'g'); 
    f = g; 
} 

E l'ho compilato con ottimizzazioni it abili:

$ g++ -o test -O3 main.cpp ; ./test 

Questo è uscita:

Test RVO: 

Test named RVO: 

Test PassByValue: 
*** COPY *** 

Test assignment: 
*** COPY *** 
*** ASSIGNMENT *** 

Secondo l'uscita RVO e il lavoro RVO nominato come previsto. Tuttavia, la copia elision non viene eseguita per l'operatore di assegnazione e quando si chiama PassByValue.

L'elisione della copia non è consentita sui costruttori di copia definiti dall'utente? (So ​​che RVO è esplicitamente consentito dallo standard, ma non conosco copia elision quando si passa per valore.) Esiste un modo per verificare la copia elision senza definire i costruttori di copia?

+1

Giusto per essere chiari, (N) RVO * è * copia elisione. Non sono le uniche forme, ma per dire che il tuo esempio mostra che la copia di elision non viene eseguita è imprecisa. –

+0

L'elisione del cooy è generalmente consentita per tutti gli oggetti temporanei, ma non per oggetti con o senza riferimento. Sembra che gcc esegua esattamente i permessi. –

+0

@Dennis Grazie Zickefoose, ho corretto il testo. – StackedCrooked

risposta

9

Il modo in cui si utilizza il costruttore di copie non può essere eliminato, poiché l'oggetto copiato esiste ancora dopo la chiamata.

Se si tenta in questo modo, potrebbe funzionare meglio:

PassByValue(Foo(512, 'a')); 

tutte le ottimizzazioni sono ammessi, ma non richiesto, quindi spetta a ciascun compilatore per decidere che cosa può e vuole fare.

+0

L'ottimizzazione viene effettivamente eseguita qui. Questo esempio insieme alla risposta di @ Space_C0wb0y mi fa capire. – StackedCrooked

10

Lo standard dice (al punto 12.8.15):

Questa elisione delle operazioni di copia è consentita nei seguenti circostanze (che possono essere combinati per eliminare più copie):

  • in una dichiarazione di ritorno in una funzione con un tipo di ritorno classe , quando l'espressione è il nome di un non volatile automatico di oggetti con lo stesso tipo cv-qualificato come tipo di ritorno della funzione , l'operazione di copia può essere omesso costruendo l' automatico di oggetti direttamente nel valore ritorno della funzione

  • quando una classe temporanea oggetto che non è stato legato ad un riferimento (12.2) sarebbe copiato in un oggetto classe con lo stesso tipo cv-qualificato, l'operazione di copia può essere omesso dal creazione dell'oggetto ranea tempo- direttamente nella destinazione della copia omesso

Nessuno di questi casi si applica qui, quindi l'elisione non è consentito. Il primo è ovvio (nessun ritorno). Il secondo non è permesso, perché l'oggetto che passi non è temporaneo.

Si noti che il codice è ancora valido, perché si dovrebbe comunque creare la copia. Per eliminare quella copia, dovresti usare la semantica del movimento di C++ 0x.

+1

In C++ 11 il numero di sezione diventa §12.8/31 e ci sono altre 2 circostanze in cui è consentito l'elisione di copia/spostamento, ma quelle sono relative solo alla gestione delle eccezioni. – kennytm

Problemi correlati