2013-04-08 1 views
6

I ++ progetti Uniti C:Copia elision e temporanei legati-by-ref oggetto

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

(...)

  • quando un oggetto di classe temporanea che non è stato legato a un riferimento (12.2) sarebbe copiato/spostato per un oggetto di classe con lo stesso tipo cv-qualificato, l'operazione di copia/spostamento può essere omesso dal costruire l'oggetto temporaneo direttamente nella destinazione della copia omessa/spostare

In altre parole:

X MakeX() { 
    return X(); // Copy elided 
} 

X MakeX() { 
    const X& x = X(); // Copy not elided 
    return x; 
} 

Qual è la ragione di tale restrizione per i riferimenti?

Si prega di non concentrarsi sulla validità dei seguenti esempi, in quanto sono solo per esemplificare che non riesco a vedere la differenza (IMHO) tra temporanea e un riferimento.

Da una parte dall'introduzione del riferimento abbiamo permesso ad altri peer di creare un alias dello stesso oggetto, mentre il chiamante di MakeX() si aspetta che sia sicuro e pulito.

class Y { 
public: 
    Y(const X& x) : _xRef(x) {} 
private: 
    const X& _xRef; 
}; 

X MakeX() { 
    const X& x = X(); 
    Y y{x}; 
    StaticStuff::send(y); 
    return x; // Oops, I promised to return a clean, 
       // new object, but in fact it might be silently 
       // changed by someone else. 
} 

Ma per quanto riguarda questo caso (probabilmente si tratta di UB;)):

class Y { 
public: 
    Y(X* x) : _xPtr(x) {} 
private: 
    X* _xRef; 
}; 

X MakeX() { 
    X x; 
    Y y{&x}; // I'm referencing a local object but I know it will be 
      // copy elided so present in the outer stack frame. 
    StaticStuff::send(y); 
    return x; // Copy elided? 
} 
+2

'StaticStuff :: send (y);' in realtà non introduce la possibilità di modificare 'x' indirettamente => il suo comportamento indefinito usa un riferimento a' x' dopo la fine di 'MakeX'. –

+1

'Oops, ho promesso di restituire un oggetto nuovo e pulito, ma in effetti potrebbe essere cambiato silenziosamente da qualcun altro. - Cosa intendi? 'x' è' const X & 'quindi non modificabile. –

+0

la tua seconda versione di 'MakeX' probabilmente invocherebbe il costruttore di copie per trasformare' const X &' in una semplice 'X', è questo il problema che hai? – didierc

risposta

3

Non si può mai sapere che una copia verrà tralasciata. Copia elision non è mai obbligatoria.

Pertanto, entrambi i casi sono UB o nessuno. Dipende da cosa fa StaticStuff:send con l'oggetto che si passa. Se mantiene qualsiasi poitner/riferimento a y._xRef o *y._xPtr, quindi il riferimento di riferimento a quel puntatore/riferimento dopo MakeX() verrà restituito causerà effettivamente UB, come l'oggetto originale x era uno con archiviazione automatica durata all'interno di MakeX() e la sua durata è ora terminata.

È possibile che il risultato di questo UB sia "tutto funziona bene" perché l'ellenizzazione della copia è avvenuta e il puntatore/riferimento si riferisce all'istanza nel "frame di stack esterno". Tuttavia, questa è pura coincidenza ed è ancora UB.

+0

Certo, lo standard afferma che "L'elisione (...) è * permessa *", quindi non posso aspettarmi nulla, e sì, in quei due casi, mi muovo nella terra dell'UB. Quello che volevo dire è che non vedo una ragione particolare per cui const ref (che è l'unico modo per conservare i provvisori) non è permesso, mentre è temporaneo. –

+0

Non penso che sia abbastanza corretto, almeno non in C++ 11. Cosa succede se 'X' è costruibile in movimento ma non copiabile? Quindi, il primo esempio dell'OP sarebbe ancora compilato e il compilatore sarà costretto a fare una 'move elision', giusto? Si prega di consultare anche http://stackoverflow.com/questions/18609968/is-default-constructor-elision-assignment-elision-possible-in-principle per i dettagli – eold

+0

@leden Io non seguo abbastanza. C'è ** no ** modo di ** forzare ** una copia/mossa elision per accadere. Quelli sono * sempre * opzionali. – Angew

Problemi correlati