tipos partes los estructura como argumentos argumento argumentacion argumenta c++ c++11 constructor copy move

c++ - los - partes de un argumento



¿Debo mover siempre en los argumentos del constructor o definidor `sink`? (2)

struct TestConstRef { std::string str; Test(const std::string& mStr) : str{mStr} { } }; struct TestMove { std::string str; Test(std::string mStr) : str{std::move(mStr)} { } };

Después de ver GoingNative 2013, entendí que los argumentos de sumidero siempre deberían pasarse por valor y moverse con std::move . ¿Es TestMove::ctor la forma correcta de aplicar este lenguaje? ¿Hay algún caso en el que TestConstRef::ctor sea ​​mejor / más eficiente?

¿Qué pasa con los colocadores triviales? ¿Debo usar el siguiente idioma o pasar un const std::string& ?

struct TestSetter { std::string str; void setStr(std::string mStr) { str = std::move(str); } };


La respuesta simple es: sí.

El motivo también es bastante simple: si almacena por valor, es posible que necesite mover (desde un temporal) o hacer una copia (desde un valor l). Examinemos lo que sucede en ambas situaciones, con ambas formas.

De un temporal

  • Si tomas el argumento por const-ref, el temporal está vinculado a const-ref y no se puede mover de nuevo, por lo que terminas haciendo una copia (inútil).
  • Si toma el argumento por valor, el valor se inicializa desde el temporal (mover), y luego usted mismo se mueve desde el argumento, por lo que no se realiza ninguna copia.

Una limitación: una clase sin un constructor de movimientos eficiente (como std::array<T, N> ) porque entonces hizo dos copias en lugar de una.

Desde un valor-l (o const temporal, pero quién haría eso ...)

  • Si toma el argumento por const-ref, no ocurre nada allí, y luego lo copia (no se puede mover de él), por lo que se hace una sola copia.
  • Si toma el argumento por valor, cópielo en el argumento y luego muévalo, por lo que se crea una única copia.

Una limitación: las mismas ... clases para las que moverse es similar a copiar.

Entonces, la respuesta simple es que, en la mayoría de los casos, al usar un receptor se evitan copias innecesarias (reemplazándolas por movimientos).

La única limitación son las clases para las que el constructor de movimientos es tan caro (o casi tan caro) como el constructor de copias; en cuyo caso, tener dos movimientos en lugar de una copia es "peor". Afortunadamente, estas clases son raras (las matrices son un caso).


Un poco tarde, ya que esta pregunta ya tiene una respuesta aceptada, pero de todos modos ... aquí hay una alternativa:

struct Test { std::string str; Test(std::string&& mStr) : str{std::move(mStr)} { } // 1 Test(const std::string& mStr) : str{mStr} { } // 2 };

¿Por qué sería eso mejor? Considere los dos casos:

De un temporal (caso // 1 )

Solo se llama un constructor de movimiento para str .

De un valor l (caso // 2 )

Sólo se llama un constructor de copia para str .

Probablemente no pueda ser mejor que eso.

Pero espera, hay más:

¡No se genera ningún código adicional en el lado de la persona que llama ! La llamada del constructor de copia o movimiento (que puede estar en línea o no) ahora puede vivir en la implementación de la función llamada (aquí: Test::Test ) y, por lo tanto, solo se requiere una copia de ese código. Si usa el paso del parámetro por valor, el llamante es responsable de producir el objeto que se pasa a la función. Esto podría acumularse en grandes proyectos e intento evitarlo si es posible.