c++ c++11 copy-elision

c++ - ¿Cómo aplicar elision de copia, por qué no funciona con el constructor de copia eliminado?



c++11 copy-elision (3)

Tengo una clase que no se puede copiar. Copiar esto sería problemático. Quiero garantizar que nunca se copiará, por lo que hice que se deleted su constructor de copia:

class A { public: A(); A(const A&) = delete; }; A fun() { return A(); }; int main() { A a = fun(); };

Desafortunadamente, g ++ no compilará esto por la razón:

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; ^

Pero esta es una situación muy clara en la que se debe usar elision de copia, por lo que nunca se debe llamar al constructor de copia. ¿Por que es esto entonces?


Hasta que C ++ 17 copy elision sea una optimización que el compilador no debe hacer, entonces las clases deben poder copiarse ya que el compilador puede querer copiar (incluso si en realidad no lo hace). En C ++ 17, la elección de copias estará garantizada en muchos casos y luego las clases no necesitarán controladores de copia.

Ver también:

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/ (el bit sobre "Elision de copia garantizada")

¿Tal vez podría usar el viejo truco de declarar el constructor de copia en su clase pero no implementarlo realmente? Eso debería complacer al compilador siempre que no invoque la copia ctor. No probé eso, pero creo que debería funcionar para su caso hasta que llegue C ++ 17.


La optimización del valor de retorno (RVO y NRVO) no significa el requisito de que se eliminen los tipos involucrados en copiables o móviles. Este requisito se aplica, ya sea que obtenga RVO o no.

La razón más probable por la que esto ocurre es que la resolución de la copia no se aplica (actualmente). Es una optimización que puede tener lugar, y no tendría sentido que el código se compile o no en función de si esa optimización se aplica en una implementación particular.

En C ++ 17, RVO se aplicará en algunas circunstancias, y se eliminarán los requisitos de copia y movilidad.


No puede forzar la copia de la elision (todavía) (ver otras respuestas).

Sin embargo, puede proporcionar un constructor de movimiento predeterminado para su clase, esto moverá (y por lo tanto, no copiará) el valor de retorno si RVO / NRVO no es posible. Para hacer esto debes agregar = default para tus constructores de movimientos:

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

Example