valores tipos salida retornan referencias referencia que punteros por parametros parametro funciones funcion entrada con c++ c++11 rvalue-reference move-constructor

c++ - tipos - ¿Debe un constructor de movimientos tomar una referencia de valor constante o no constante?



que es un parametro en c++ (4)

Además de lo que se dice en otras respuestas, a veces hay razones para que un constructor de movimientos o una función acepte una const T&& . Por ejemplo, si pasa el resultado de una función que devuelve un objeto const por valor a un constructor, se llamará T(const T&) lugar de T(T&&) como probablemente se esperaría (vea la función g continuación).

Esta es la razón detrás de eliminar las sobrecargas que aceptan const T&& para std::ref y std::cref lugar de las que aceptan T&& .

Específicamente, el orden de preferencia durante la resolución de sobrecarga es el siguiente:

struct s {}; void f ( s&); // #1 void f (const s&); // #2 void f ( s&&); // #3 void f (const s&&); // #4 const s g (); s x; const s cx; f (s ()); // rvalue #3, #4, #2 f (g ()); // const rvalue #4, #2 f (x); // lvalue #1, #2 f (cx); // const lvalue #2

Vea este artículo para más detalles.

En varios lugares he visto las firmas recomendadas de copiar y mover constructores dadas como:

struct T { T(); T(const T& other); T(T&& other); };

Donde el constructor de copia toma una referencia constante, y el constructor de movimiento toma una referencia de valor no constante.

Sin embargo, por lo que puedo ver, esto me impide aprovechar las ventajas de la semántica de movimientos cuando devuelvo objetos const de una función, como en el caso a continuación:

T generate_t() { const T t; return t; }

Probando esto con VC11 Beta, se llama al constructor de copia de T , y no al constructor de movimiento. Incluso utilizando return std::move(t); El constructor de copia todavía se llama.

Puedo ver cómo esto tiene sentido, ya que t es constante, por lo que no debería vincularse a T&& . El uso de const T&& en la firma del constructor de movimiento funciona bien y tiene sentido, pero luego tiene el problema de que al ser other , no puede anular a sus miembros si necesitan ser anulados, solo funcionará cuando todos los miembros son escalares o tienen constructores de mudanzas con la firma correcta.

Parece que es la única manera de asegurarse de que se llame al constructor de movimientos en el caso general para que haya hecho t no constantes en primer lugar, pero no me gusta hacer eso: contradecir las cosas es una buena forma y no esperaría El cliente de T debe saber que tuvo que ir en contra de esa forma para aumentar el rendimiento.

Entonces, supongo que mi pregunta es doble; Primero, ¿debería un constructor de movimientos tomar una referencia de valor constante o no constante? Y segundo: ¿estoy en lo cierto en esta línea de razonamiento? ¿Que debería dejar de devolver las cosas que son constantes?


Debe ser una referencia no const .

Si un objeto se coloca en la memoria de solo lectura, no puede robarle recursos, incluso si su vida útil formal está finalizando en breve. Los objetos creados como const en C ++ pueden vivir en la memoria de solo lectura (usar const_cast para intentar cambiarlos da como resultado un comportamiento indefinido).


Un constructor de movimientos normalmente debería tomar una referencia no constante.

Si fuera posible moverse desde un objeto constante, por lo general implicaría que era tan eficiente copiar un objeto como "moverse" desde él. En este punto, normalmente no hay beneficio de tener un constructor de movimientos.

También tiene razón de que si tiene una variable de la que posiblemente desee mover, entonces no será constante.

Según tengo entendido, esta es la razón por la que Scott Meyers ha cambiado su consejo sobre la devolución de objetos de tipo de clase por valor de las funciones para C ++ 11. La devolución de objetos por el valor cualificado de const impide la modificación involuntaria de un objeto temporal, pero también impide el movimiento del valor de retorno.


¿Debe un constructor de movimientos tomar una referencia de valor constante o no constante?

Se debe tomar una referencia no constante . En primer lugar, las referencias de valor no tienen sentido en sus formas constantes simplemente porque desea modificarlas (de alguna manera, quiere "moverlas" , quiere sus partes internas para usted).

Además, han sido diseñados para ser utilizados sin const, y creo que el único uso para una referencia constante es algo muy arcano que Scott Meyers mencionó en this charla.

¿Estoy justo en esta línea de razonamiento? ¿Que debería dejar de devolver las cosas que son constantes?

Creo que esta es una pregunta demasiado general para responder. En este contexto, creo que vale la pena mencionar que hay una funcionalidad std::forward que preservará tanto el valor de valor como el valor de valor así como la constancia y evitará la creación de una función temporal como lo haría si regresara cualquier cosa que se le pase.

Este retorno también causaría que la referencia de valor se "transforme" en la referencia de valor y generalmente no desea que, por lo tanto, un reenvío perfecto con la funcionalidad mencionada anteriormente resuelve el problema.

Dicho esto, le sugiero que simplemente eche un vistazo a la charla en la que publiqué un enlace.