When exactly is destructor being called? Initially, I thought that destructor were supposed to be called when we use the:
delete [] str;
Then, when I came accross the "move assignment" topic, I notice that the destructor is called directly after I NULL my rhs.str in my move assignment method.
main.cpp
int main() {
Mystring a{"Hello"};                // Overloaded constructor
a = Mystring{"Hola"};              // Overloaded constructor then move assignment
// cout << a.get_str() << endl;
a = "Bonjour";                         // Overloaded constructor then move assignment
return 0;
}
Mystring.h
#ifndef _MYSTRING_H_
#define _MYSTRING_H_
class Mystring
{
private:
    char *str;      // pointer to a char[] that holds a C-style string
public:
    Mystring();                                            // No-args constructor
    Mystring(const char *s);                                     // Overloaded constructor
    Mystring(const Mystring &source);                    // Copy constructor
    Mystring(Mystring &&source);                         // Move constructor
    ~Mystring();                                                     // Destructor
    Mystring &operator=(const Mystring &rhs); // Copy assignment
    Mystring &operator=(Mystring &&rhs);        // Move assignment
    void display() const;
    int get_length() const;                                       // getters
    const char *get_str() const;
};
#endif // _MYSTRING_H_
Mystring.cpp
// No-args constructor
Mystring::Mystring() 
    : str{nullptr} {
    str = new char[1];
    *str = '\0';
}
// Overloaded constructor
Mystring::Mystring(const char *s) 
    : str {nullptr} {
    if (s==nullptr) {
    str = new char[1];
    *str = '\0';
    } else {
        str = new char[strlen(s)+1];
        strcpy(str, s);
    }
}
// Copy constructor
Mystring::Mystring(const Mystring &source) 
    : str{nullptr} {
    str = new char[strlen(source.str)+ 1];
    strcpy(str, source.str);
    std::cout << "Copy constructor used" << std::endl;
}
// Move constructor
Mystring::Mystring(Mystring &&source) 
     : str(source.str) 
    {
         source.str = nullptr;
         std::cout << "Move constructor used" << std::endl;
    }
 // Destructor
Mystring::~Mystring() 
{
    if (str == nullptr) {
    std::cout << "Calling destructor for Mystring : nullptr" << std::endl;
    } else {
    std::cout << "Calling destructor for Mystring : " << str << std::endl;
}
    delete [] str;
}
 // Copy assignment
Mystring &Mystring::operator=(const Mystring &rhs) {
    std::cout << "Using copy assignment" << std::endl;
    if (this == &rhs) 
        return *this;
    delete [] str;
    str = new char[strlen(rhs.str) + 1];
    strcpy(str, rhs.str);
    return *this;
}
//Move assignment
Mystring &Mystring::operator=(Mystring &&rhs) {
    std::cout << "Using move assignment" << std::endl;
    if (this == &rhs) 
        return *this;
    delete [] this->str;
    this->str = rhs.str;
    rhs.str = nullptr;
    return *this;
}
The output is as follow:
Using move assignment
Calling destructor for Mystring : nullptr
Using move assignment
Calling destructor for Mystring : nullptr
Calling destructor for Mystring : Bonjour
I have tried debugging but I just have no idea why it went into the Destructor method when I did not explicitly called the
delete [] str  // or maybe
delete [] rhs.str 
As you can see in the output, my r-value is deleted after every move assignment. I thought that every object should at least be deleted before the return 0;