'Why program stops after constructor?

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



Solution 1:[1]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Revolver_Ocelot