¿Cómo exactamente debería un constructor de copia para alguna clase X asignar un valor a la nueva copia de un objeto que produce? Esta respuesta asume que el objeto involucrado es una variable miembro de la clase X. Lo que sigue favorece la simplicidad pero evita muchos detalles. Aquí hay un resumen ejecutivo: probablemente no debería usar el operador de asignación en un constructor de copia. Otras opciones son preferibles.
C ++ ahora admite la semántica de movimiento, y esta capacidad se puede usar para copiar una instancia de un objeto. Con C ++ 11, es posible proporcionar una asignación de movimiento y un operador de asignación de copia para cualquier clase no trivial. Esta característica adicional avanza el objetivo principal de diseño de C ++ para evitar copias y temporarios innecesarios. Cuando se usa correctamente, la semántica de movimiento puede producir mejoras significativas en el rendimiento.
clase X {
privado:
int * val;
público:
// constructor de copia (C ++ 98)
X (const X y lv): val (lv.val) {}
// mover constructor (C ++ 98 y C ++ 11)
X (X && rv): val (std :: move (rhs.val)) {
rhs.val = nullptr; // deja rhs en estado válido
};
// asignación de copia (C ++ 98)
X y operador = (const X y lv) {
if (this == & lv) {
volver (* esto);
}
val = lv.val;
volver (* esto);
};
// mover asignación (C ++ 98 y C ++ 11)
X & operator = (X && rv) {
val = nullptr; // indefinir valor actual
val = std :: move (rv.val); // solicita movimiento, toma el valor rhs
rv.val = nullptr; // deja rhs en estado válido
volver (* esto);
}
};
La función std :: move () se declara en , pero no mueve nada. En cambio, convierte su argumento en una referencia de valor de r , que es un tipo declarado con dos símbolos: X &&. (Los valores son temporales o valores anónimos que aparecen solo en el lado derecho de una tarea). Cuando ya no se necesita un objeto, puede convertirlo en una referencia de valor y luego transferir la propiedad de sus contenidos y / o recursos a otro objeto para su uso posterior.
- ¿Cómo particionar un conjunto múltiple de enteros positivos en tres subconjuntos de modo que se minimice la diferencia entre las sumas de subconjuntos máximas y mínimas?
- ¿Cuáles son algunas aplicaciones del algoritmo Aho Corsaik en la programación competitiva?
- Cómo resolver [matemáticas] x + y + z = a, x ^ 2 + y ^ 2 + z ^ 2 = b, x ^ 3 + y ^ 3 + z ^ 3 = c [/ matemáticas] para [matemáticas] x , y, z [/ matemáticas]
- Cómo resolver esta pregunta de aptitud matemática
- ¿Cómo se llama Android N?
Tenga en cuenta que la técnica preferida para la asignación de variables miembro en un constructor de copia es a través de la inicialización (ver línea 6). Esto es parcialmente por el bien del rendimiento: la asignación de una variable primero debe desasignar la memoria previamente asignada a esa variable. Posteriormente, la asignación asigna memoria para el nuevo valor. Un constructor de copias puede evitar esta contabilidad innecesaria inicializando la variable miembro durante la construcción en la lista de inicialización, una mejora de la eficiencia.
Si por alguna razón es necesaria la asignación, el cuerpo del constructor de copia puede invocar una función de asignación de copia para una variable miembro en lugar de usar la lista de inicialización. Es posible que esta técnica no pase la revisión del código.
Las operaciones de copiar y mover toman diferentes parámetros de función. Como se muestra arriba, el conocido constructor de copias y el operador de asignación para la clase X toman un parámetro de tipo const X & (líneas 6 y 12). El constructor de movimientos y el operador de asignación de movimientos toman un parámetro de tipo X && (líneas 8 y 17). Para inicializar una nueva variable miembro, las funciones de movimiento llaman a un constructor de movimiento (líneas 8 y 19), que transfiere la propiedad de El valor del argumento pasado para inicializar la variable miembro. Esto es trivial para la clase X, pero para los tipos complejos definidos por el usuario, puede ser una mejora de eficiencia deseable porque, en lugar de crear una copia de todos los elementos, std :: move () asigna la memoria interna al nuevo objeto.
Tenga en cuenta que el programador debe asegurarse de que cualquier modificación (especialmente la destrucción del objeto del que se tomó el valor) no afecte el estado del nuevo objeto que posteriormente posee el valor. Es una buena práctica borrar el contenido del argumento pasado (por ejemplo, asignando nullptr a sus miembros internos).
Si una clase no proporciona semántica de movimiento y solo tiene el constructor de copia y el operador de asignación de copia habituales, entonces estas funciones se llamarán para referencias de valor. Por lo tanto, una llamada a std :: move () invoca mover semántica, si se proporciona, y copiar semántica de lo contrario.