How come my destructor is not destroying my object and it still retains its member variable values?

103 views Asked by At

In my code I don't understand why my derived class object is not being destroyed even though I called the destructor explicitly. I don't know if its because I didn't include delete or something to do with the scope but can you help me out? I added comments in my code to help illustrate my issue

In my header file I have:

#ifndef test_test_h
#define test_test_h

#include <iostream>
#include <string>

using namespace std;


class test{
public:
    test();
    void setName();
    string getName();
private:
    string name;
};

class book:public test{
public:
    book();
    ~book();
    void setBook();
    string getBook();
private:
    string bookName;
};

#endif

In my implementation file I have:

#include "test.h"

test::test()
{
    cout<<"calling base construtor"<<endl;
    name="hi";

}

book::book()
{
    cout<<"Calling derived constructor"<<endl;
    bookName="yolo";
}


test::~test()
{
    cout<<"calling test destructor"<<endl;
}


book::~book()
{
    cout<<"calling  book destructor"<<endl;
}




void test::setName()
{
    cout<<"Input name"<<endl;
    cin>>name;

}

string test::getName()
{
    return name;
}

void book::setBook()
{
    cout<<"Input name"<<endl;
    cin>>bookName;

}

string book::getBook()
{
    return bookName;
}

In my main file I have:

#include "test.h"

int main(){


    book b;

    b.setBook();

    cout<<b.getBook()<<endl;//takes user input
    cout<<b.getBook()<<endl;//displays the input u put in

    b.~book();

    cout<<b.getBook()<<endl;//for some reason it still prints out whatever you inputed even though I called the destructor earlier. I would think it would display yolo because that string is saved in the constructor of book
}
2

There are 2 answers

0
R Sahu On

First of all, don't call the destructor explicitly for variables with automatic storage. The destructor will be called automatically when you exit the scope in which the variable is defined.

After you call,

b.~book();

b is an invalid object.

Using b after that is cause for undefined behavior. The line after that is not guaranteed to behave in any predictable manner.

You have:

cout<<b.getBook()<<endl;//for some reason it still prints out whatever you inputed even though I called the destructor earlier. I would think it would display yolo because that string is saved in the constructor of book

Since the program is subject to undefined behavior, it is pointless trying to make sense of what it does.

Also, the destructor will be called on b when the function returns, which will lead to undefined behavior.

0
gavinb On

for some reason it still prints out whatever you inputed even though I called the destructor earlier.

The destructor method doesn't deallocate the object or clear the memory used by the member variables. It is simply an opportunity for you to release resources allocated during the lifetime of the instance.

I would think it would display yolo because that string is saved in the constructor of book

That is the first thing that happens to the object, not the last. The state of the object doesn't return to the constructed state after being destroyed; it is undefined. The last change will likely remain in memory.

Once an object has been destroyed by the runtime, the contents of the memory that was allocated to it is undefined. Since it is potentially quite expensive to zero out the memory whenever an object is destroyed, most implementations leave the contents of memory as is, and it will simply be left to be overwritten by some later usage. This is why you were able to print out the book name after having called the destructor.

Here is the main function, annotated with some comments to illustrate:

#include "test.h"

int main(){

    // 1. Allocate a book object on the stack
    book b;

    // 2. b.bookName = "yolo"    
    b.setBook();

    cout<<b.getBook()<<endl;
    // 3. bookName = "user input"

    // Wrong! But calls the destructor method which just prints a message
    b.~book();

    // 4. displays "user input"
    cout<<b.getBook()<<endl;

    // b goes out of scope and ~book() will be called automatically
}

You should not call the destructor manually. For objects allocated on the stack (automatic allocation, as here) the object will be destroyed when the variable goes out of scope (at the end of the block) and the destructor will be called.

For objects allocated on the heap, you destroy an object by calling delete which will call the destructor for you and then release the memory back to the system. This too is not guaranteed to zero out the memory; it is typically flagged as unused and available for reuse.

Your code displays the same book name value because the book instance is still on the stack at the time it is printed, since calling the destructor manually doesn't actually free or zero the memory.