Advertisement

Object Usage and Destructors

Started by June 05, 2017 01:36 PM
24 comments, last by Josheir 7 years, 5 months ago

Hello everyone, I have been banging my head trying to understand the following. First, let me note that the correct way of doing this would be with smart pointers, but my curiosity has really gotten the better of me!

Here is my code : https://paste.ofcode.org/guvXn7iz5tWtZ6mRHEdR2S

I am trying to understand why these objects are not calling the destructors: (maybe the keyword new and delete are always needed in these cases?) I couldn't find any examples without these keywords or smart pointers. I know, I know, use smart pointers instead.

A testObject1

AtestObject2

B* testObA;

B testObb;

A test_1;

A * test_2;

B * testOb1;

B testOb2;

//THIS ONE DID CALL "destructor," why?

A testObjA;

A * testObjB;

Thank you so much,

Josheir

I assume you are asking why there is no destructor call to A::~A() for "testObjA?"

That's because testObjA isn't an A, it's a pointer-to-an-A. There are no destructors to execute for pointers, just like there are no destructors to execute for other basic language types like integers and floats.

Letting a bare pointer-to-A (or any other bare pointer type) go out of scope does not invoke the destructor for A on that instance (as that instance is not an A).

Advertisement

It's not clear exactly what you're asking since there are a bunch of different variables there, and that's too complex a test case to examine in detail. 4 variables created in main, 4 more in func, then you call func from main - that's potentially 8 things you could be asking about. But I'll tell you what I see.

When you create a local instance of a variable inside a function - e.g. B testOb2() - , it gets destroyed when it goes out of scope (i.e. when the function returns), so its own destuctor will be called.

When you create a member variable - e.g. A testObject1 inside Class B - that variable gets destroyed when the enclosing object is destroyed.

When you create a pointer to something - e.g. B * testObA - you haven't actually created an object, just a pointer that could hypothetically refer to one. The same applies to creating a member pointer. Just like any variable, when it goes out of scope or is destroyed, its destructor is called, but a pointer's destructor does nothing.

This is where smart pointers come in - the reason we call them smart, is because they do have a destructor, and what that destructor does is destroy the object that they own. This prevents that object 'leaking', i.e. being allocated but completely unusable, thereby wasting memory.

Note that none of your pointers actually own or refer to anything at all, so there is nothing to leak. However, they're also completely useless as-is.

C and C++ only delete data that is in a scope which is about to be left. Bare pointers in a scope that is being left are deleted too, that is, only the pointer itself, not the data it points to. C and C++ don't track if data was malloc-ed (or new-ed), or if you created a pointer to some variable, like


{
  int i;
  {
    int *p = &i;
    *p = 3;
  } // Leaving scope, delete p (only the pointer, not i).
    // "delete &i;" is not allowed, as "i" was never "new-ed".

  printf("i=%d\n", i); // This would fail too if i would be destroyed.
} // destroy i

Similarly, you may setup several pointers to the same block of memory. C/C++ doesn't track that information, it's your responsibility to make sure you delete the memory just before destroying the last pointer to it.

Reference-basd languages, like Python, C#, and Java do track references to a block of data (in several different ways), and can detect all the above cases, and release memory for you.

For C/C++ you can use Boehm's garbage collector.

Well, first of your code here is different to whats in your link:


B * testObA;
B testObB();
A test_1; // destructor called
A * test_2;

So you are now asking why only line 3 calls the destructor, if I am right? Thats quite simple:

- "B* testObA" declares a pointer to an object of type B, not an object itself. As a pointer just stores the address of another object, obviously it does not call the destructor, with doing:


B * testObA = new B; // creates & assigns an object of Type B
delete testObA; // deletes the object pointed to by testObA => calls the destructor

(you're actually right that you should rather use unique_ptr in that case :) )

- The second line "B testObB();", at least how it is the code you linked, does not declare a variable of type B eigther, it declares a function pointer with the signature "B (*)(void)". Yeah, having empty brakes like that when declaring a variable does not call the constructor but instead modifies the type of the variable. So when you remove the (), it should construct & destruct the object properly.

Point 2 can actually be misleading, but pointers are pretty basic C++-stuff, so I think this thread rather belongs to for beginners; and on that note you should read up on basic concepts of c++ memory "management" like pointer, references etc... from how it appears :)


And yes, moving to For Beginners.

Advertisement

OK, than so if I needed to destroy a dynamically allocated object in p_Object and p_Object is in another object, How would I destroy p_Object's contained dynamic objects when p_Objects containing class goes out of scope.

Thanks again,

Josheir

That's what a destructor is for. Object A's destructor is there to allow you to clean up anything that Object A allocated during its lifetime. So, if you used `new` to allocate some sub-objects (e.g. in the constructor, or anywhere else), you use `delete` in the destructor to destroy those sub-objects.

I've really made a mess of this.

My code was not printing out the destructor calls and it now is.

Basically though if a pointer to an object doesn't call the destructor than how can it's subobjects be deleted?

thanks,

Josheir

The object that contains the pointer is responsible for that pointer, and for whatever the pointer refers to. So it must destroy that sub-object, within its own destructor.

eg.


class A
{
private:
    B* objB;

public:
    A()
    {
        objB = new B();
    }

    ~A()
    {
        delete objB;
    }
}

This topic is closed to new replies.

Advertisement