Modismo de copiar e intercambiar en C++

Antes de profundizar, primero echemos un vistazo al ‘operador de asignación sobrecargado’ normal que usamos.

// Simple C++ program to demonstrate overloading of
// assignment operator.
#include <iostream>
#include <cstring>
using namespace std;
  
class anyArrayClass
{
    int size;
    int *ptr;
public:
  
    // Initializer list
    anyArrayClass(int s=0):size(s),
        ptr(size? new int[size]:nullptr) {}
  
    // Copy constructor
    anyArrayClass(const anyArrayClass& obj):size(obj.size),
        ptr(size? new int[size]:nullptr)
    {
        memmove(ptr, obj.ptr, size*sizeof(int));
    }
  
    // Overloaded assignment operator
    anyArrayClass& operator=(const anyArrayClass& obj)
    {
        // self assignment check
        if (this != &obj)
        {
            delete ptr;
            size = obj.size;
            ptr = size? new int[size]: nullptr;
            memmove(ptr, obj.ptr, size*sizeof(int));
            return *this;
        }
    }
    ~anyArrayClass()
    {
        delete[] ptr;
    }
}

El operador de asignación anterior hace lo siguiente:
1. Comprobación de autoasignación.
2. Si la asignación no es para uno mismo, entonces sigue.
    a) Desasignar memoria asignada a this->ptr
    b) Asignar nueva memoria a this->ptr y copiar los valores
    c) Devolver *this

Inconvenientes del enfoque anterior:

  1. La verificación de autoasignación: la autoasignación se realiza muy raramente, por lo que la verificación de autoasignación no es relevante en la mayoría de los escenarios. Esto solo ralentiza el código.
  2. Desasignación y asignación de memoria: como se puede ver, primero se desasigna la memoria (dejando el puntero colgando) y luego se asigna la nueva porción de memoria. Ahora, si por alguna razón la memoria no está asignada y se lanza una excepción, el ‘this->ptr’ quedará colgando apuntando a una memoria desasignada. El escenario debe ser que la asignación sea exitosa o que el objeto no se altere en absoluto.

Aquí viene el papel del enfoque de copiar e intercambiar. Este enfoque resuelve elegantemente el problema anterior y también proporciona un alcance para la reutilización del código. Veamos qué es exactamente.

Considere el siguiente código:

// Simple C++ program to demonstrate use of copy-and-swap
// idiom by improving above code.
#include <iostream>
#include <cstring>
using namespace std;
  
class anyArrayClass
{
    int size;
    int *ptr;
public:
    anyArrayClass(int s=0):size(s),
     ptr(size? new int[size]:nullptr) {}
  
    // Copy constructor
    anyArrayClass(const anyArrayClass& obj):size(obj.size),
                           ptr(size? new int[size]:nullptr)
    {
        memmove(ptr, obj.ptr, size*sizeof(int));
    }
  
    friend void swap(anyArrayClass& obj1, anyArrayClass& obj2)
    {
        std::swap(obj1.size, obj2.size);
        std::swap(obj1.ptr, obj2.ptr);
    }
      
    // overloaded assignment operator
    // argument passed by value. calls copy ctor
    anyArrayClass& operator=(anyArrayClass obj)    
    {
        // calling friend function
        swap(*this, obj);
        return *this;
    }
  
    ~anyArrayClass()
    {
        delete[] ptr;
    }
}

En el ejemplo anterior, el parámetro para el ‘operador =()’ se pasa por valor que llama al constructor de copia para crear un objeto anyArrayClass local para el ‘operador =()’. Luego, el valor del objeto temporal se intercambia con el objeto ‘*this’ (lado izquierdo de la llamada del operador de asignación).

ventajas:

  1. No se necesita más verificación de autoasignación ya que el parámetro se pasa por valor (esto significa que no se necesita más desasignación de memoria). Además, dado que la autoasignación es muy rara, la sobrecarga de copiar en caso de autoasignación no debería ser un problema.
  2. Ahora, como el constructor de copia se usa para crear el objeto temporal, por lo tanto, el intercambio solo se realizará si se crea el objeto temporal. Básicamente, lo que estábamos haciendo manualmente allí, el compilador lo está haciendo por nosotros aquí.
  3. Reutilización del código: como podemos ver, el ‘operador =()’ no tiene mucho código en su cuerpo, estamos usando el constructor de copia y la función de intercambio para hacer el trabajo.

Este artículo es una contribución de Bishwa Nath . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *