← SEARCHABLE ARCHIVE
C / C++ · 2026-07-30

C++ de los fundamentos al dominio — Lección 14

¿Cuál es la diferencia entre copiar y mover?

INTERACTIVE READING MODE →

Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.

Parece que se producirán muchas copias al insertar un objeto grande en un vector o al devolver un objeto desde una función. En C++ se distingue entre copiar, que duplica el valor tal cual, y movimiento, que se hace cargo de los recursos de un objeto que ya no se necesita.

Copiar

La copia crea un nuevo objeto con los mismos valores que el original.

class Texture
{
public:
    explicit Texture(std::vector<unsigned char> pixels)
        : pixels(std::move(pixels))
    {
    }

private:
    std::vector<unsigned char> pixels;
};

Texture original(LoadPixels());
Texture copied = original;

copiedCuando se crea un vector, los datos dentro del vector también se copian. Dado que los dos objetos son independientes entre sí, modificar el copiado no cambia el original.

Los valores pequeños tienen poco costo de copia, pero los objetos con grandes buffers o muchas cadenas pueden resultar costosos.

movimiento

Si el original ya no se utiliza, los recursos internos se pueden pasar a un nuevo objeto.

Texture loaded(LoadPixels());
Texture equipped = std::move(loaded);

std::moveno transfiere datos directamente. Cambiamos el objeto para tratarlo como un valor móvil, y el trabajo real lo realiza el constructor de movimiento o el operador de asignación de movimiento.

emocionadoloadedTodavía se puede destruir y se pueden asignar nuevos valores. Sin embargo, no debes esperar que el estado interno sea el mismo que antes.

loaded = Texture(LoadPixels()); //Es posible sustituir un nuevo valor.

Rule of Zero

Si administra la memoria directamente con nuevo y eliminar, debe considerar copiar el constructor, copiar la asignación, mover el constructor, mover la asignación y el destructor juntos. Si incluso uno se implementa incorrectamente, se puede producir doble liberación o pérdidas de memoria.

class CharacterData
{
public:
    std::string name;
    std::vector<int> learnedSkills;
    std::unique_ptr<Weapon> weapon;
};

Utilizando contenedores estándar y punteros inteligentes como miembros, cada tipo gestiona sus propios recursos. Este método de no escribir funciones miembro especiales directamente se llama Regla de Cero.

Unique_ptr no se puede copiar; sólo se puede mover. Esta limitación evita la duplicación accidental de la propiedad exclusiva en la etapa de compilación.

Cómo pasar valores

Objetos grandes que solo leenconst T&Cuando una función toma posesión, a menudo se utiliza el método de recibirla como un valor y luego moverla.

class Party
{
public:
    void Add(CharacterData character)
    {
        members.push_back(std::move(character));
    }

private:
    std::vector<CharacterData> members;
};

Party party;
CharacterData warrior;
party.Add(std::move(warrior));

CharacterData tiene Unique_ptr como miembro, por lo que no se puede copiar, solo se puede mover. Al agregar un objeto existente, debe pasar la propiedad usando std::move o pasar un objeto temporal.

Agregar std::move a todas partes no es óptimo.

Primero debe decidir si es un valor que debe copiarse o si es un valor del que puede transferir la propiedad. Mover no es una sintaxis para copiar rápidamente, sino más bien una expresión de no depender del estado original después de transferir recursos.