How are constructors and destructors implemented in C++? - c++

I have 2 classes Base and Derived (derived publically from Base).
When I write -
Derived * d1 = new Derived;
delete d1;
Compiler sees that d1 is a Derived type object. So it calls the derived class constructor (which calls the base class constructor). I have 2 questions here -
1) Why do we follow this order?
2) How do these constructors work together to allocate memory? I need some implementation details
Now the next statement is delete d1. So compiler sees that d1 is a derived type object and so calls the destuctor of derived class (which calls the destructor of base class after deleting the derived class members). I have one question here -
1) How do these destructors work together? Lets say the derived class destructor is passed the address of d1 in memory. How do these destructors free up the space now?

That code will not compile. You cannot deletean automatic instance, you must use new to allocate the instance in order to use delete on it.
When it comes to constructor order, I guess it just makes sense to run them so that more specialized classes can depend on the more general parts having already been done.
The memory layout of each class is known by the compiler, from inspecting the complete class declaration and recursing up through any and all superclasses.

1) By default, the base class constructor is called automatically. However, the derived constructor is allowed to call the base class constructor explicitly in its initializer list. This would not be possible if the constructors were not executed derived-class-first.
Derived::Derived() : foo( 42 ), bar( 7 ), Base( 1, 2 ) { }
2) The compiler knows the memory footprint of the derived class (as all member variables are known at compile time), and allocates enough memory to hold both the base class and the derived class members. Details on the memory layout are specified by the ABI used by your system.
3) Destructors do more than just freeing up the memory. Actually, the destructors do not free up memory required to hold any member variables - only, where necessary, memory that member pointers point to.

(1) The base class does not depend on the derived class, but the other way around is possible. I.e. a Base class cannot know which fields any Derived class has, so Base::Base won't and can't touch them. The other way around is possible, Derived::Derived can access Base::member. Therefore, Base::member is initialized by Base::Base before Derived::Derived gets the chance to useBase::member`.
(2) constructors don't allocate memory. That's new's task. Or if the object is a global, the compilers'. The constructor is called with this already pointing to the allocated memory; it need just fill in the members at that location.
In the case of a base and derived constructor, one common implementation inserts the call to the Base constructor in the generated code for the Derived constructor. With single inheritance, the Base and Derived class usually share the same this pointer, so the Derived constrcutor can then pass the same pointer that it got.
(1) [sic] Just like constructors don't allocate memory, destructors don't free it. That's the task of delete - and again, for globals the compiler would do it.

The code example you give wouldn't compile. delete works on pointers, not objects.
I don't think C++ itself (the language standard) says anything about how memory is used to represent instances of types that use inheritance. However, in most implementations a single chunk of memory is allocated from the free store that is large enough to hold all the data of Base and Derived. When an instance of Derived is deleted, both constructors run and then the single memory block is freed.
Similarly, if an instance of Derived is an embedded data member of some class Container, then the memory block that holds an instance of Container will be made large enough to hold Derived (and hence Base) and all the other data of Container.

When constructing, constructors are called from the highest base class until the oneof the most derived, which will be called the latest.
When destructors are called, it's the reverse order. First is called the destuctor of the most derived, until the one of the highest base class.

While in inheritance, the compiler should know what it is inheriting. It should know what the Base class consists of. It cannot inherit from a class, which it doesn't have any idea..
So, it does make sense that the Base class constructor is called first and then the Derived.
And in the case of Destruction, if the Base destructor is being called first and gets destructed, the Derived class may still be using the Base class members which becomes invalid.. Hence the Destruction is the exact inverse of the construction..

Related

Why the inheritance of a class with non-virtual destructor is not a good thing even if the derived class adds no members?

In this answer answer:
In particular, you are not allowed to delete a std::vector<T>* that
actually points at a derived object (even if the derived class adds no
members), yet the compiler generally can't warn you about it.
I understand that virtual destructor is needed if the object will be deleted through a base pointer. That's to let each class destroy it's members (at least I think so). But if the class don't have any members in itself, then why it shouldn't be deleted through the base pointer?
And also, how do I force some class to be accessed only through a pointer with it's type and not with one of the bases? will this make it normal to inherit from a class with a non-virtual destructor?

Virtual destructor use cases

I' ve read some articles, and as they say, main virtual destructor use cases are:
derived classes may have dynamic data allocation from heap, i.e. "own" that data object. So, they need some deletion routine in destructor. Deletion through base class pointer requires virtual declaration of destructors in all derived class till those with dynamic data allocation (base class also requires it)
this class has virtual methods. But this is unclear for me. Just calling virtual methods through base class pointer always results in the-most-derived-realization calls. They only exclusion for that rule is construction phase. Literaly, during it this object is not a derived type yet, even if later will be. Ok, what about destruction phase? As I understood, the rule is in the backward order. No matter, was destructor of some class in hierarchy declared as virtual, during each destructor this pointer is used as if of this class type, any derived were already been destroyed due to virtual d-r, or not destroyed (and that hypothetically may be ok in some design). Maybe this is the case, why d-r must be virtual? Vtable will have entries for derived class, and calling virtual methods in some base class from d-r will result in UB? Ok, but this rule applies only to case when this class calls some virtual methods in d-r, and they do have realization in derived classes.
My opinion, that there is also may be a case with no dynamic data allocation, no virtual methods in all hierarchy, but still derived destructors may do some critical tasks upon deletion (syncs, unlocks and so on). And we need virtual d-r in base class. May be such cases are results of bad design.
But anyway, developer of some public class cannot 100% know, if derived class will or not use some virtual methods in d-r, or allocate dynamic data. So, am I correct to say, that any public class, not declared as final, has to declare d-r as virtual? Only final keyword guarantees that any pointer to this class will always be of this type, and so, could be safely deleted non-virtually.
If a derived object is deleted through a pointer to the base class, then (and only then) the base class destructor must be virtual. Otherwise it is undefined behaviour. There are no other relevant rules.
If the class had a virtual function anyway, then no overhead is introduced. If the class did not have any other virtual functions, then the base class designer has to consider the trade between adding the runtime penalty of a virtual destructor, vs. the risk that a user of the class might try to delete a derived object through the base class pointer.
Here is a link to a similar discussion, with Standard quotes

Memory management with pointers created using "new" in C++

I have a base class where 2 pointers are declared in the header. The pointers are then initialized with the "new" keyword in a method of the base class and deleted with "delete" in the destructor of the base class.
I also have a derived class that inherits from the base class. I declare a pointer there as well. Depending on a boolean, this pointer is assigned to either pointer of the base class. However, this results in a segfault when the destructor of the base class is called.
My understanding is that this happens because the derived class will delete the pointer automatically before the destructor of the base class is called. When "delete" is called in the base class, then this area of memory has already been freed and a segfault results.
What is the correct way of doing this? My aim is to have a pointer in the derived class that can flexibly equal one of the pointers initialized in the base class.
Either do not delete the pointer in the derived class or use standard smart pointer std::shared_ptr
Your base class should probably have a virtual destructor, then you should override the destructor in your derived class to make sure everything gets deleted in the order you expect.
But it's hard to tell what's happening without seeing the code, so that's just a thought...

Freeing abstract class pointers

In C++ I have a class A that has an abstract class pointer to allow for polymorphism contained in a class B, I have another pointer to an abstract class C that allocates a concrete instance of a child class of class B into that memory and I need to call a cleanup (see question below) function from class C to deallocate the memory taken by the child class of class B that I allocated from the heap, the problem is I can't guarantee I have access to the cleanup function because I only have a pointer to class C which I can't just copy, because it could be gone by the time I call need to destroy the containing class A.
In order to solve the problem of not having access to the cleanup function can I call delete on the class A pointer even though I'm pointing to a child class? Does C++ new also store heap block size like malloc so that you can just delete memory referenced by a pointer to an abstract class like this? If not is there another way to organize the program that allows me to handle the situation?
I'm using my crystal ball because it's hard to follow your question but you probably need virtual destructors.
The standard states (§5.3.5 ¶3):
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
If I understood correctly, you have an object of some derived type, and you hold a pointer to it whose static type is one of its base classes; so, you're ok, as far as you have virtual destructors.
Edit well, I was way too slow :P

Virtual destructor: is it required when not dynamically allocated memory?

Do we need a virtual destructor if my classes do not allocate any memory dynamically ?
e.g.
class A
{
private:
int a;
int b;
public:
A();
~A();
};
class B: public A
{
private:
int c;
int d;
public:
B();
~B();
};
In this case do we need to mark A's destructor as virtual ?
The issue is not whether your classes allocate memory dynamically. It is if a user of the classes allocates a B object via an A pointer and then deletes it:
A * a = new B;
delete a;
In this case, if there is no virtual destructor for A, the C++ Standard says that your program exhibits undefined behaviour. This is not a good thing.
This behaviour is specified in section 5.3.5/3 of the Standard (here referring to delete):
if the static type of the operand is
different from its dynamic type, the
static type shall be a base class of
the operand’s dynamic type and the
static type shall have a virtual
destructor or the behavior is
undefined.
The purpose of virtual destructor (i.e. the purpose of making a destructor virtual) is to facilitate the polymorphic deletion of objects through delete-expression. If your design does not call for polymorphic deletion of objects, you don't need virtual destructors. Referring to your example, if you'll ever have to delete an object of type B through a pointer of type A * (polymorphic deletion), you'll need virtual destructor as high up in the hierarchy as A. That's how it looks from a formal point of view.
(Note, BTW, as Neil said, that what's important is how you create/delete your class objects, not how classes manage their internal memory.)
As for the good programming practices... It depends on your intent and your design in the end. If your classes are not designed to be polymorphic at all (no virtual methods whatsoever), then you don't need virtual destructors. If your class is polymorphic (have at least one virtual method), then making the destructor virtual "just in case" might be a very good idea, and in this case it bears virtually zero performance/memory penalty with it.
The latter is usually expressed as a rather well-known good practice guideline: if your class has at least one virtual method, make the destructor virtual as well. Although from the formal point of view a virtual destructor might not be really needed there, it is still a pretty good guideline to follow.
Classes that have no resources but can form polymorphic hierarchies should always define empty virtual destructors, except that it is perfectly sufficient to define an explicit empty (and even pure) virtual destructor at the very base of the hierarchy. All other destructors will become virtual automatically, even if they are defined implictly by the compiler. I.e. you don't have to explicitly define an empty destructor in every class. Just the base is enough.
Freeing memory is not the only critical function a destructor can perform. It can also be used to reset global state for instance. Not doing this won't leak memory but could potentially cause other issues in your program.
Additionally, even if your destructor doesn't do anything useful today, it may at some point in the future. There's no real reason to avoid a virtual destructor if you have inheritance so why not just add it and sleep better at night?
The destructor of the parent class is always automatically called, and the default dtor is always generated if there's no explicit dtor declared. In your example, neither A nor B needs to have a non-trivial dtor.
If you class has virtual functions, an additional virtual dtor doesn't hurt, and is good practice. In case you class allocates memory or any other resource (like opening a file), a dtor is needed to free that resource again upon destruction.
The purpose of declaring destructor as virtual is to be able to invoke the derived class's destructor whenever you call delete on a pointer of type Base which is pointing to object of type Derived. Not doing so would result in undefined behavior.
The assumption that you need not mark destructor as virtual if you are not allocating memory dynamically implies that you do not need to call derived class destructor if you are not allocating memory dynamically, which is wrong. As you may still do several other operations in your derived class's destructor other than just deallocating the dynamically allocated memory. Examples would be closing an open file, logging some information etc.
If your only concern is memory, maybe you should start by protecting base class destructor (and/or maybe others). Then if something does not compile, you'll see why. Ref: boost::any ways.