C ++ dynamic objects. How is the size of an object determined at runtime?

I do not understand anything. For example, I declare class A and class B, which is a child of A:

class A { public: int a; } class B : public A { public: int b; } 

Obviously, if I create instances of A or B, their size in memory can be determined by type.

 A instanceA; // size of this will probably be the size of int (property a) B instanceB; // size of this will probably be twice the size of int (properties a and b) 

But what if I create dynamic instances and then release them later?

 A * instanceAPointer = new A(); A * instanceBPointer = new B(); 

These are instances of different classes, but the program will consider them as instances of class A. This is great when using them, but how to free them? To free allocated memory, a program must know the size of free memory, right?

So if I write

 delete instanceAPointer; delete isntanceBPointer; 

As the program knows, how much memory, starting from the address pointed to by the pointer, should it free? Because, obviously, the objects are of different sizes, but the program considers them to be of type A.

thanks

+5
source share
3 answers

I am going to suggest that you know how to remove works .

How delete knows how to clear an inherited instance. This is why you use a virtual destructor in the context of inheritance, otherwise you will have undefined behavior. In principle, a destructor, like any other virtual function, is called via vtable .

Also remember that: the C ++ compiler implicitly destroys the parent class in your destructor

 class A { public: int a; virtual ~A(){} } class B : public A { public: int b; ~B() { /* The compiler will call ~A() at the very end of this scope */ } } 

That is why it will work;

 A* a = new B(); delete a; 

Using vtable destructor ~B() will be called delete . Because the compiler implicitly inserts the destructor call of the base class (s) into the derived class (es), the destructor A will be called in ~B() .

+6
source

The behavior is undefined if you delete an object using a pointer to the underlying subobject, and the subobject class does not have a virtual destructor.

On the other hand, if it has a virtual destructor, then the virtual dispatch mechanism will take care of freeing the correct amount of memory for the correct address (i.e. for the full, most derived object).

You can find the address of the most derived object yourself by applying dynamic_cast<void*> to any corresponding base subobject pointer. (See also this question .)

+3
source

To free allocated memory, a program must know the size of free memory, right?

If you consider the C library malloc and free , you will see that there is no need to specify the amount of freed memory when calling free , although in this case free provided with void* , so there is no way to do this. Instead, distribution libraries usually either write to or can output enough information about the provided memory, so one pointer is enough to free.

This remains true with C ++ release routines: if the base class provides its own static void operator delete(void*, std::size_t) and the base class destructor virtual , then the size of the dynamic type will be passed to it. By default, the release ends with ::operator delete(void*) , which will not be of any size: the distribution procedures themselves must know enough to work.

There are many ways in which distribution procedures can be performed, including:

  • saving selection size

  • selection of objects of the same size from the pool of identical pieces, so any pointer to this pool implicitly refers to the size of the block

+2
source

All Articles