Si reservo el vector con cierto tamaño, entonces tengo un ciclo donde tomo la variable local y luego emplace_back(std::move(local_object)), ya que std::move transfiero la propiedad de la memoria. ¿Tendrá el vector los elementos con ubicaciones consecutivas?

c++
0
debonair 26 may. 2020 a las 08:16

4 respuestas

vector siempre usa ubicaciones de memoria consecutivas (contiguas). Pero si std::move realmente está ayudando, lo más probable es que sus objetos no almacenen su propia memoria de forma local (con algunos de los datos almacenados en memoria asignada dinámicamente), y esa memoria no local permanecerá no local (los punteros a él se mueven como parte de la construcción del movimiento, pero el punto al que permanece permanece sin cambios).

En resumen, las partes que no se benefician de move serán contiguas, y las partes que se benefician de move permanecerán donde estaban.

1
ShadowRanger 26 may. 2020 a las 05:21

Un vector siempre almacena elementos en ubicaciones consecutivas.

Cuando agrega nuevos elementos, es posible que vector necesite asignar nueva memoria y reubicar los datos para que los elementos encajen en ubicaciones consecutivas.

El paso reserve realiza una asignación de memoria y se garantiza que podrá agregar la cantidad de elementos para los que ha reservado espacio sin reubicaciones.

std::move no mueve nada. Se utiliza en local_object para indicar que puede ser movido desde lo que hace que el constructor de movimiento sea elegible. Es el constructor de movimiento el que hace la transferencia de propiedad real.

Si tiene punteros en bruto en su objeto, debe escribir los constructores de copiar y mover usted mismo (así como los operadores de asignación de copiar y mover). Consulte la regla de 5.

1
Ted Lyngmo 26 may. 2020 a las 05:39

Mueve el contenido de la memoria de local_object, no mueve mágicamente la memoria en sí. El vector tiene su propio almacenamiento que siempre es continuo.

2
wilx 26 may. 2020 a las 05:19

Esas no son reglas del lenguaje, sino conceptos arquitectónicos:

  • Debe recordar que el almacenamiento ocupado por un objeto no es propiedad de dicho objeto. Es propiedad de algo jerárquicamente más alto. Ese puede ser otro objeto o proceso, o una función en caso de almacenamiento automático.

  • Tomar posesión de la memoria dinámica asignada supone tomar el control del puntero devuelto por una nueva expresión. Una vez ganado, se controla hasta que el titular de ese valor y para dejar de existir, se debe "eliminar". De lo contrario, se "perderá", lo que provocará la llamada pérdida de memoria. Pero se prefiere considerar el término "propiedad del recurso" para abolir los detalles de implementación y designar que una entidad particular tiene acceso a dicho recurso y controla su "vida".

Para analizar la expresión emplace_back(std::move(local_object)) uno debe considerar que

  1. Vector no posee recursos de objetos almacenados. Se necesita el propietario del recurso utilizado para almacenar objetos.

  2. Si un objeto almacenado de tipo T posee algunos recursos, NO están transfiriendo la propiedad al contenedor. Siguen siendo dueños de ellos.

  3. emplace_back construye un objeto nuevo de tipo T en la ubicación de memoria propiedad de vector si hay espacio disponible. De lo contrario, reasignaría el almacenamiento de vector para obtener el recurso requerido. Los argumentos de emplace_back se usan como argumentos de constructor para el tipo T.

  4. std::move no mueve nada. Es un mnemónico estandarizado para una expresión xvalue , equivalente a la conversión estática del resultado de la expresión utilizada como argumento para un tipo rvalue reference .

  5. Como el argumento de emplace_back es una referencia rvalue al objeto original de tipo T, se invoca el llamado "constructor de movimiento". Si el usuario definió el constructor para el tipo T, entonces es responsabilidad del usuario qué acción se realizó después de la asignación finalizada del vector.

  6. Si no se definieron constructores de movimiento y copia definidos por el usuario y operadores de asignación para T, tampoco hay un destructor definido por el usuario, entonces el compilador declara implícitamente el constructor de movimientos. El constructor de movimiento declarado implícitamente sigue una semántica definida para todos los miembros, en orden de declaración:

    • Para todos los subobjetos de tipo clase, se llaman los constructores de movimiento, comenzando con el subobjeto de clase base, si corresponde.
    • Para todos los tipos y matrices fundamentales, se copia el contenido de su almacenamiento.
  7. El constructor de movimiento declarado implícitamente se define como eliminado si T contiene cualquier miembro no estático de T que no sea móvil, clase base directa o virtual que no sea móvil, o si T es una clase tipo unión y tiene un miembro con usuario definido mover constructor.

  8. La capacidad para moverse implica la presencia de acceso a un constructor de movimiento inequívoco y no eliminado en el contexto actual.

Por lo tanto, emplace_back daría como resultado la transferencia de la propiedad del objeto original de tipo T al objeto recién construido , solo si el usuario hubiera definido el constructor de movimiento para el objeto de tipo T o cualquiera de sus subobjetos y Todo el conglomerado es móvil. Si no se cumple ese requisito, se considerará la construcción de un nuevo objeto por llamada del constructor de copias. De lo contrario, no es más que una copia superficial.

0
Swift - Friday Pie 26 may. 2020 a las 07:25