Sobrecarga del operador +

Iniciado por MAFUS, 25 Diciembre 2021, 20:58 PM

0 Miembros y 1 Visitante están viendo este tema.

MAFUS

Buenas, chavales. Feliz Navidad y aniversario de Newton.

Estaba yo haciendo prácticas de C++ (le voy a dar una oportunidad) y no llego a entender del todo porqué saca unos resultados tan raros.

El código:
Código (cpp) [Seleccionar]
#include <iostream>

class vector {
private:
    int *n;
    int tamano;

public:
    vector(int tamano = 5);
    ~vector();
    void visualizar();
    void llenar();
    vector operator + (vector &);
    int& operator[] (int i) { return n[i]; };
};

vector::vector(int t):tamano(t) {
    n = new int[tamano];
    llenar();
}

vector::~vector() {
    delete[] n;
}

vector vector::operator + (vector &v) {
    vector resultado(tamano);
    for(int i=0; i<tamano; ++i) {
        resultado[i] = n[i] + v[i];
    }
    return resultado;
}

void vector::visualizar() {
    for(int i=0; i<tamano; ++i) {
        std::cout << n[i] << '\t';
    }
    std::cout << std::endl;
}

void vector::llenar() {
    for(int i=0; i<tamano; ++i) {
        n[i] = rand() % 10;
    }
}

int main() {
    vector a, b;
    a.visualizar();
    b.visualizar();
   
    vector c;
    c = a + b;
    c.visualizar();
   
    vector d = a + b;
    d.visualizar();

    return 0;
}


El resultado:
1       7       4       0       9
4       8       8       2       4
1577824 0       1573200 0       13
5       15      12      2       13


Es decir: porqué 'c' no y 'd' sí.

Eternal Idol

Basicamente estas accediendo a memoria ya liberada.

https://en.cppreference.com/w/cpp/language/rule_of_three

Supongamos que:

Código (c++) [Seleccionar]
vector::vector(int t):tamano(t) {
    n = new int[tamano];
    std::cout << "ctor n " << n << " object " << this << std::endl;
    llenar();
}
     
vector::~vector() {
    std::cout << "dtor n " << n << " object " << this << std::endl;
    delete[] n;
}



Código (c++) [Seleccionar]
int main() {
    vector a, b;
    a.visualizar();
    b.visualizar();
    vector z = a;


ctor n 0000020069C0A6E0 object 000000C9E96FF838 //constructor de a
ctor n 0000020069C0A720 object 000000C9E96FF848 //constructor de b
1       7       4       0       9
4       8       8       2       4
dtor n 0000020069C0A6E0 object 000000C9E96FF878 //destructor de z!
dtor n 0000020069C0A720 object 000000C9E96FF848 //destructor de b
dtor n 0000020069C0A6E0 object 000000C9E96FF838 //destructor de a

"Because C++ copies and copy-assigns objects of user-defined types in various situations (passing/returning by value, manipulating a container, etc), these special member functions will be called, if accessible, and if they are not user-defined, they are implicitly-defined by the compiler."

¿Que definio el compilador para el constructor de copia? Una copia byte por byte:

Código (asm) [Seleccionar]
  0003c 48 8d 44 24 68 lea rax, QWORD PTR z$[rsp]
  00041 48 8d 4c 24 28 lea rcx, QWORD PTR a$[rsp]
  00046 48 8b f8 mov rdi, rax
  00049 48 8b f1 mov rsi, rcx
  0004c b9 10 00 00 00 mov ecx, 16
  00051 f3 a4 rep movsb


Por eso z.n es igual a a.n y eso no es bueno ya que se terminara liberando dos veces.

Si lo definimos nosotros:
Código (c++) [Seleccionar]
vector(const vector &r) : vector(r.tamano)
{
    memcpy(n, r.n, tamano * sizeof(int));
}


ctor n 0000025A0CD6A820 object 000000935CFCFB88 //a
ctor n 0000025A0CD6A740 object 000000935CFCFB98 //b
1       7       4       0       9
4       8       8       2       4
ctor n 0000025A0CD6A760 object 000000935CFCFBC8 //z
dtor n 0000025A0CD6A760 object 000000935CFCFBC8 //~z
dtor n 0000025A0CD6A740 object 000000935CFCFB98 //~b
dtor n 0000025A0CD6A820 object 000000935CFCFB88 //~a

Ahora pasamos a probar:

Código (c++) [Seleccionar]
vector c;
c = a + b;
c.visualizar();



Y comento el delete[] del destructor para que no explote el programa.

ctor n 0x8d13f0 object 0x79fdf0 //a
ctor n 0x8d1410 object 0x79fde0 //b
1       7       4       0       9
4       8       8       2       4
ctor n 0x8d1870 object 0x79fdd0 //c
ctor n 0x8d1890 object 0x79fe00 //resultado
dtor n 0x8d1890 object 0x79fe00 //~resultado
9263792 0       9240912 0       13
dtor n 0x8d1890 object 0x79fdd0 //~c

¿Cual es el problema? El operador de asignacion definido por el compilador hace que c.n sea igual a resultado.n (un n que inmediatamente es liberado al ejecutarse el destructor del objeto resultado).

Fijate si podes implementarlo siguiendo la logica demostrada en el enlace del principio de mi mensaje.

Tendrias que llegar a algo asi con el main original:

ctor n 0xae13f0 object 0x79fdf0 //a
ctor n 0xae1410 object 0x79fde0 //b
1       7       4       0       9
4       8       8       2       4
ctor n 0xae1870 object 0x79fdd0 //c
ctor n 0xae1890 object 0x79fe00 //resultado
ope= n 0xae1870 object 0x79fdd0 //c = resultado
dtor n 0xae1890 object 0x79fe00 //~resultado
5       15      12      2       13
ctor n 0xae1890 object 0x79fdc0 //d y resultado son lo mismo en este caso, esta optimizada la asignacion y por eso funciona  :-X
5       15      12      2       13
dtor n 0xae1890 object 0x79fdc0 ;~d
dtor n 0xae1870 object 0x79fdd0 ;~c
dtor n 0xae1410 object 0x79fde0 ;~b
dtor n 0xae13f0 object 0x79fdf0 ;~a
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

MAFUS

Entiendo. Me olía que por ahí iban los tiros. Ocurren tantas cosas que uno llega a perder el hilo de lo que va sucediendo  ;D ;D


Gracias

Eternal Idol

De nadas  ::) Y eso es con el codigo optimizado por el compilador, podria ser asi en debug:

ctor n 0000023ACEFD8FE0 object 000000C8C87FFE78
ctor n 0000023ACF023FE0 object 000000C8C87FFE68
1       7       4       0       9
4       8       8       2       4
ctor n 0000023ACF029FE0 object 000000C8C87FFE98
ctor n 0000023ACF02FFE0 object 000000C8C87FFE18
ctor n 0000023ACF035FE0 object 000000C8C87FFEA8
copy n 0000023ACF035FE0 object 000000C8C87FFEA8
dtor n 0000023ACF02FFE0 object 000000C8C87FFE18
ope= n 0000023ACF029FE0 object 000000C8C87FFE98
dtor n 0000023ACF035FE0 object 000000C8C87FFEA8
5       15      12      2       13
ctor n 0000023ACF04DFE0 object 000000C8C87FFE18
ctor n 0000023ACF053FE0 object 000000C8C87FFE88
copy n 0000023ACF053FE0 object 000000C8C87FFE88
dtor n 0000023ACF04DFE0 object 000000C8C87FFE18
5       15      12      2       13
dtor n 0000023ACF053FE0 object 000000C8C87FFE88
dtor n 0000023ACF047FE0 object 000000C8C87FFE98
dtor n 0000023ACF023FE0 object 000000C8C87FFE68
dtor n 0000023ACEFD8FE0 object 000000C8C87FFE78
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón