Search code examples
c++dereference

Alias of variable not working in operator overloading


I am learning operator overloading. I am trying to overload + operator in my code. When I am returning with implicit de-referencing, the output is gibberish.

If I explicit de-reference the variable when returning, it is working properly. Is the issue happening because I am referencing some temporary variable and it is destroyed, after coming out of the scope. If so, then why is explicit de-reference working? P.S. : I am aware that I can return without reference and I am not following rule of 3 in the code.


class ComplexNum
{
private:
    int real, imaginary;
public:
    ComplexNum();
    ComplexNum(int x, int y);
    ComplexNum(const ComplexNum& other);
    ~ComplexNum();

    int getReal() const;
    int getImaginary() const;

    const ComplexNum& operator=(const ComplexNum&);
    friend std::ostream& operator <<(std::ostream& out, const ComplexNum& a);
    ComplexNum& operator+(const ComplexNum&);
};

ComplexNum::ComplexNum()
{
}

ComplexNum::ComplexNum(int x, int y):real(x), imaginary(y)
{
}

ComplexNum::ComplexNum(const ComplexNum& other)
{
    this->real = other.real;
    this->imaginary = other.imaginary;
}

ComplexNum::~ComplexNum()
{
}


int ComplexNum::getReal() const
{
    return real;
}

int ComplexNum::getImaginary() const
{
    return this->imaginary;
}

const ComplexNum& ComplexNum::operator=(const ComplexNum& other)
{
    real = other.real;
    imaginary = other.imaginary;

    return *this;
}

ComplexNum& ComplexNum::operator+(const ComplexNum& other)
{
    ComplexNum a(real + other.getReal(), imaginary + other.getImaginary());
    return a;
}

/*the above one doesn't work but the below commented out works fine.*/
/*
ComplexNum& ComplexNum::operator+(const ComplexNum& other)
{
    ComplexNum* a = new ComplexNum(real + other.getReal(), imaginary + other.getImaginary());
    return *a;
}*/

std::ostream& operator<<(std::ostream& out,const ComplexNum& a)
{
    out << a.real << " & " << a.imaginary << "j";
    return out;
}


/*Here is how I am calling it in main*/
int main()
{
    ComplexNum complex(3, 4);
    ComplexNum c2(5, 6);
    cout << c2 << endl;
    ComplexNum& c3 = c2 + complex;
/*getting error in the below code. c3 is o/p gibberish value as if not initialized*/
    cout << c3<< " " << c2 << endl;
    return 0;
}

I am getting gibberish value, as if the the variable c3 is not initialized.


Solution

  • This code here causes a memory leak, because the pointer a is automatically deleted once the end of scope is reached and you have no way to delete the memory allocated in the heap by new. Unluckily for you, you dereferenced a right before it got deleted in the return statement, and you were able to access its' value, thinking that everything was alright.

    ComplexNum& ComplexNum::operator+(const ComplexNum& other)
    {
        ComplexNum* a = new ComplexNum(real + other.getReal(), imaginary + other.getImaginary());
        return *a;
    }
    

    To be honest, most of the code you have can be elided by using the = default specifier or not having them at all. Use it because it makes the code easy to read.

    Operators that are used to return a new instance of the class (ex. +,-,*,/), should not be returned by reference. Operators that modify the current instance of the class (ex. =,+=,-=,*=,/=), should be returned by reference.

    #include <iostream>
    
    struct ComplexNum
    {
        int real;
        int imaginary;
    
        ComplexNum() = default;
        ComplexNum(int x, int y) : real(x), imaginary(y)
        {;}
    
        friend std::ostream& operator <<(std::ostream& out, const ComplexNum& a)
        {
            out << a.real << " & " << a.imaginary << "j";
            return out;
        }
    
        ComplexNum operator + (const ComplexNum &other)
        {
            int r = this->real + other.real;
            int i = this->imaginary + other.imaginary;
            return ComplexNum(r,i);
        }
    
        ComplexNum& operator += (const ComplexNum &other)
        {
            this->real += other.real;
            this->imaginary += other.imaginary;
            return *this;
        }
    
        ~ComplexNum() = default;
    };
    
    
    int main()
    {
        ComplexNum c1(3, 4);
        std::cout << c1 << std::endl;
    
        ComplexNum c2(5, 6);
        std::cout << c2 << std::endl;
    
        ComplexNum c3 = c1 + c2;
        std::cout << c3 << std::endl;
    
        c3 += c1;
        std::cout << c3 << std::endl;
    }
    

    Results:

    3 & 4j
    5 & 6j
    8 & 10j
    11 & 14j
    

    Online code example: https://rextester.com/QNR88316