2016-07-06 1 views
7

Ho una classe non classificabile. Copiare questo sarebbe problematico. Voglio garanzia che non sarà mai copiato, così ho fatto il suo costruttore di copia deleted:Come applicare la copia elision, perché non funzionerà con il costruttore di copie cancellato?

class A { 
    public: 
    A(); 
    A(const A&) = delete; 
}; 

A fun() { 
    return A(); 
}; 

int main() { 
    A a = fun(); 
}; 

Purtroppo, g ++ non verrà compilato questo sul motivo:

t.cc: In function ‘A fun()’: 
t.cc:8:12: error: use of deleted function ‘A::A(const A&)’ 
    return A(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^
t.cc: In function ‘int main()’: 
t.cc:12:13: error: use of deleted function ‘A::A(const A&)’ 
    A a = fun(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^

Ma questa è una situazione molto chiara in cui si dovrebbe usare copy elision, quindi il costruttore di copia non dovrebbe mai essere chiamato. Perché è così?

+1

Attendi fino a C++ 17, forse sarà garantito –

+0

Whoops. Spostato per rispondere. –

+1

Jesper non sta ripetendo la tua risposta, non hai menzionato le modifiche imminenti fino ai nostri commenti –

risposta

9

Fino a C++ 17 copia elision è un'ottimizzazione che il compilatore non è tenuto a fare, quindi le classi devono essere copiabili poiché il compilatore potrebbe voler copiare (anche se in realtà non lo fa). In C++ 17 la copia elisione sarà garantita in molti casi e quindi le classi non avranno bisogno di copiatori.

Consulta anche:

http://en.cppreference.com/w/cpp/language/copy_elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/ (il bit di "elisione copia Garantito")

Si potrebbe forse usare il vecchio trucco di dichiarare il costruttore di copia in la tua classe ma non la realizzi effettivamente? Questo dovrebbe soddisfare il compilatore a patto che non invochi effettivamente il copy ctor. Non l'ho provato, ma credo che dovrebbe funzionare per il tuo caso fino a quando arriva C++ 17.

8

Non è possibile forzare la copia elisione (ancora) (vedere altre risposte).

Tuttavia, è possibile fornire un costruttore di spostamento predefinito per la classe, in tal modo si sposterà (e quindi non copierà) il valore restituito se RVO/NRVO non è possibile. Per fare questo si dovrebbe aggiungere = default per i vostri costruttori mossa:

class A { 
    public: 
    A() = default; 
    A(const A&) = delete; 
    A(A&&) = default; 
    A& operator=(A&&) = default; 
}; 

Example

+0

Non riesco a capire il basso, soprattutto senza spiegazione. – peterh

+1

@peterh Probabilmente perché non risponde alla domanda che hai chiesto. – juanchopanza

+0

Ok, ma perché sono necessari i costruttori di movimento? L'unico costrutto che ha richiesto di essere chiamato in questo esempio, è il costruttore vuoto. Non si verificano effettivamente movimenti. – peterh

7

valore di ritorno di ottimizzazione (RVO e NRVO) non significa che il requisito che i tipi coinvolti dal copiabile o mobile è caduto. Questo requisito si applica, indipendentemente dal fatto che tu abbia o meno RVO.

Il motivo più probabile è che la copia elision non è (attualmente) applicata. È un'ottimizzazione che può avere e che non avrebbe senso che il codice si compilasse o meno in base al fatto che l'ottimizzazione sia applicata in una particolare implementazione.

In C++ 17, il RVO verrà applicato in alcune circostanze e i requisiti di riproducibilità e mobilità verranno eliminati.

Problemi correlati