Idioma Copy-and-Swap en C++: guía 2025 con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Qué es el idiom Copy-and-Swap y por qué es imprescindible en 2025



Imagina que estás escribiendo una clase para trabajar con memoria dinámica. Todo va bien hasta que llegas a la sobrecarga del operador de asignación. Escribes operator=, verificas la autoasignación, liberas manualmente los recursos antiguos, asignas nuevos… Y en el 90% de los casos cometes un error que provocará una fuga de memoria o una doble eliminación. ¿Te suena?



En C++ existe una solución elegante: el idiom copy-and-swap. No es solo un truco moderno, sino una técnica fundamental que permite escribir código seguro, resistente a excepciones y conciso. En 2025, cuando C++23 ya se usa activamente y el estándar C++26 está en el horizonte, este idiom sigue siendo el estándar de oro para las clases que gestionan recursos.



En este artículo, analizaremos el idiom copy-and-swap de principio a fin: desde el problema que resuelve hasta ejemplos prácticos y las mejores prácticas de 2025. ¡Prepara tu compilador, que habrá mucho código!



El problema: por qué el operator= ingenuo es malo



Comencemos con un ejemplo clásico de una clase que gestiona un arreglo dinámico. Sin el idiom copy-and-swap, el código a menudo se ve así:



class DumbArray {public:    DumbArray(size_t size)         : size_(size), data_(new int[size]) {}        ~DumbArray() { delete[] data_; }        // Operador de asignación ingenuo    DumbArray& operator=(const DumbArray& other) {        if (this == &other) return *this; // verificación de autoasignación        delete[] data_;                    // liberamos recursos antiguos        size_ = other.size_;        data_ = new int[size_];           // asignamos nuevos        std::copy(other.data_, other.data_ + size_, data_);        return *this;    }    private:    size_t size_;    int* data_;};


A primera vista, todo parece lógico. Pero hay tres problemas:

  • Falta de garantía básica de excepciones. Si new int[size_] lanza std::bad_alloc, el objeto queda en un estado incorrecto: data_ apuntará a memoria eliminada.
  • Duplicación de lógica. La copia de datos ya está implementada en el constructor de copia. ¿Por qué escribimos lo mismo manualmente?
  • Verificación de autoasignación. Ralentiza el código y es fácil de olvidar. Además, en el 95% de los casos no ocurre autoasignación, pero la verificación se ejecuta igualmente.


Y eso no es todo. Si agregas otros recursos a la clase (como descriptores de archivos o mutexes), el código no solo se vuelve voluminoso, sino peligroso. Aquí es donde entra en escena el idiom copy-and-swap.



La esencia del idiom: tres pasos hacia un operator= perfecto



El idiom copy-and-swap se basa en una idea simple: no escribas la lógica de copia en el operador de asignación; usa el constructor de copia y la función swap. El algoritmo es el siguiente:



  1. Copy: creamos una copia temporal del objeto usando el constructor de copia.
  2. Swap: intercambiamos el contenido del objeto actual con la copia temporal.
  3. Destroy: el objeto temporal se destruye, liberando los recursos antiguos.


En código, se ve así:



class SmartArray {public:    SmartArray(size_t size = 0)         : size_(size), data_(size ? new int[size] : nullptr) {}        // Constructor de copia    SmartArray(const SmartArray& other)         : size_(other.size_), data_(other.size_ ? new int[other.size_] : nullptr) {        std::copy(other.data_, other.data_ + size_, data_);    }        // Destructor    ~SmartArray() { delete[] data_; }        // Función swap amiga    friend void swap(SmartArray& first, SmartArray& second) noexcept {        using std::swap;        swap(first.size_, second.siz                

Blogs

Book Recommendations