Home > Blockchain >  Why program stops after constructor?
Why program stops after constructor?

Time:03-14

I am learning operator overloading and I read somewhere that when you assign a r-value to object then it creates a temporary object but this program stops after calling constructor for r-value.

Class.h

class Foo{
    int *num;

    public :

    Foo(int x);
    Foo& operator=(Foo &&rhs);
    Foo& operator=(const Foo &rhs);
    Foo(Foo &f);
    Foo(Foo &&f);
    void set(int x);
    void show();
    ~Foo();
    

};

Class.cpp

#include <iostream>
#include "class.h"
#include <cstring>

Foo::Foo(int x){
    num = new int;
    *num = x;
    std::cout << "Constructor for " << *num << std::endl;
};

Foo::~Foo(){
    std::cout << "Destructor for " << *num << std::endl;
    delete num;
}

void Foo::show(){
    std::cout << *num << std::endl;
}

void Foo::set(int x){ 
    *num = x;
    std::cout << "INSIDE SETTER" << std::endl;
}

Foo& Foo::operator=(Foo &&rhs){

    num = rhs.num;
    rhs.num = nullptr;
    return *this;
}

Foo& Foo::operator=(const Foo &rhs){

    *num = *rhs.num;
    return *this;
}


Foo::Foo(Foo &f){
    num = new int;
    *num = *f.num;
    std::cout << "Copy constructor used " << std::endl;
}

Foo::Foo(Foo &&f)
: num{f.num}{
    std::cout << "Move constructor used " << std::endl;
    f.num = nullptr;
}

int main(){
    Foo f1(10);
    Foo f2(20);
    Foo f3(30);
    f1.show();
    f2.show();
    f3.show();
    f1 = 60;
    f1.show();
    f2.show();
    f3.show();
    return 0;
}

Program stops after calling constructor for 60.

OUTPUT
Constructor for 10
Constructor for 20
Constructor for 30
10
20
30
Constructor for 60
[Done] exited with code=3221225477 in 1.458 seconds

It works when I use char *str instead of int *num

CodePudding user response:

Your problem is in the destructor. It tries to access *num, but move assignment operator sets num to nullptr.

Either guard logging against nullptr (there is no need to guard delete, as it is guaranteed to work properly on null pointers):

Foo::~Foo(){
    if (num) {
        std::cout << "Destructor for " << *num << std::endl;
    } else {
        std::cout << "Destructor for null pointer" << std::endl;
    }
    delete num;
}

Or use swap in move assignment and let rhs to delete it eventually(this also will fix memory leak: you never delete old value of num)

Foo& Foo::operator=(Foo &&rhs)
{
    std::swap(num, rhs.num);
    return *this;
}

Output for swap solution:

Constructor for 10
Constructor for 20
Constructor for 30
10
20
30
Constructor for 60
Destructor for 10
60
20
30
Destructor for 30
Destructor for 20
Destructor for 60
  • Related