C++: Can I use this safely in a destructor? - c++

Todays' question is: Can I use this in a destructor, and if yes what are the restrictions I must obey to... For example, I know I'm not supposed to do anything with base classes, since they are gone. But what other restrictions apply? And can I safely assume that the this (as a pointer... ie. memory address... a number) is the same as in the constructor?

Can I use this in a destructor
Yes.
For example, I know I'm not supposed to do anything with base classes, since they are gone.
No, the base classes are still intact at this point. Members (and perhaps other base classes) of derived classes have already been destroyed, but members and base classes of this class remain until after the destructor has finished.
But what other restrictions apply?
Virtual functions are dispatched according to the class currently being destroyed, not the former most-derived class. So be careful calling them, and in particular don't call any functions that are pure virtual in this class.
Don't cast this to a derived type, since it is no longer a valid object of that type.
You can't delete this from the destructor, for obvious reasons.
And can I safely assume that the this (as a pointer... ie. memory address... a number) is the same as in the constructor?
Yes, an object's address remains the same from before its constructor runs until after its destructor runs.

As answered here it's perfectly valid.
You should avoid calling virtual functions, though.

Base classes are not gone in the destructor, you can use them normally.
Derived class are gone, so in particular virtual calls will not reach derived classes.
this has the same value as in the constructor and everywhere else in the class.
The main restriction is that you should not allow any exception to leave the destructor. This means that you have no means of indicating failure[*]. Generally you should only perform operations that are certain to succeed (such as freeing resources owned by the object): anything you do that can fail, it must be OK to ignore the failure. Anything you do that can throw, you should catch the exception. Hopefully you have fully documented the possible exceptions thrown by all the functions of this, so you know whether or not the things you want to do with this can throw.
[*] well, you could build a mechanism for the destructor to record somewhere
what happened, but users of the class would have to actively check it. This is unlikely to result in a pleasant user experience.

Since objects are destructed from the most derived class down to the base, derived classes destructors will already have executed. So you must make sure not to call methods overridden in derived classes on this. Apart from that, it's fine.

Destructor is a method, which is called before your object is physically destroyed, such that you can deinitialize it properly. In order to do so, you must have access to its fields, so you can safely access them by the this keyword.
The order of destructors is reverse to the constructors, so when your destructor runs, destructors of base classes haven't run yet - you should have access to all their fields. On the other hand, destructors of derived classes have already run, so - for example - calling virtual or abstract methods may result in undefined behavior.
Additionally, keep in mind, that it's very dangerous to throw exceptions in destructors. If you do so, you risk terminating your application.

Yes you can use it normally. You have the object there.

I don't see any problem using this in the destructor. At this time, the object is still there. The destructor is for you to free existing resources before the object is destroyed.
But avoid calling virtual functions.

Related

When can I safely inherit from a base class in C++

So the basic rule that I find everywhere is that to inherit from a base class, the base class must have a virtual destructor so that the following works:
Base *base = new Inherited();
delete base;
However I am certain I have seen at least one other possibility that allows safe inheritance. However I can't find it anywhere and I feel like I am going mad trying to find it. I thought the other option might have been that the base class had a trivial destructor, but according to Non-virtual trivial destructor + Inheritance, this isn't the case. Even though there wouldn't be a memory leak for this case, it appears this is still undefined behaviour.
Does anyone else know what the other case is or can you definitively tell me that I dreamt it?
I guess an example can be the one that involves shared_ptrs, for it is good to show both the sides of the issue.
Suppose you have a class B with a trivial non virtual destructor and a derived class D with its own complex one.
Let's define the following function somewhere:
shared_ptr<B> factory () {
// some complex rules at the very end of which you decide to instantiate class D
return make_shared<D>();
}
In that case you are dealing with all the interesting features due to the polymorphism, but the pointer you are working with has inherited the deleter from the one constructed with type D.
Even though, thanks to the type erasure, the type is buried somewhere and everything works fine, the actual invoked destructor is the one of D, so everything should work fine also from that point of view, even though the destructor of B was not virtual.
Instead, if you define the above factory as:
B* factory () {
return new D{};
}
The called destructor (well, supposing that someone will delete it) will be the one of B, that is not what you want.
That said, defining as virtual the destructor of a class that is meant to be inherited from is a good practice, otherwise put a final in the class definition and stop there the hierarchy.
There also a lot of other examples, this is not the only case where it works, but it can help to explain why it works.
Perhaps when the inheritance is private. In such a case, the user can't convert Derived* to Base* so there is no chance of trying to delete the derived class through the base class pointer. Of course, you still have to watch that you don't do this anywhere within your implementation of Derived.
My take on this is pragmatic rather than anything to do with what is or isn't allowed by the standards.
So, pragmatically, if a class doesn't have a virtual destructor - even an empty one - then my default assumption is that it hasn't been designed to be used as a base class. This may have more implications than just destruction and in more cases than not, just opens a can of worms for you to fall in later.
If you want or need to use functionality from a class without a virtual destructor, it would be safer to use composition rather than inheritance. In fact, that's the preferred route anyway.
The other case I've seen mentioned is making the base-class destructor protected. That way, you prevent deletion through a base class.
This is actually item 50 in the book C++ Coding Standards by Herb Sutter et al: "Make base class destructors public and virtual or protected and non-virtual", so it is quite likely that you have heard of it before.
You can always inherit from a class. There are rules to obey though, e.g. without a virtual destructor you can't invoke the destructor polymorphically. In order to avoid this, you could e.g. use private derivation for baseclasses that were not intended as baseclasses, like e.g. the containers from the STL.
As others have mentioned, as long as you delete the class through it's own destructor - in other words you do
Inherited *ip = new Inherited();
Base *p = ip;
...
delete ip;
you'll be fine. There are several different ways to do that, but you have to be quite careful to ensure that is the case.
However, having an empty destructor in the baseclass [and your inherited type is immediately inheriting] only works as long as it is TRULY empty, and not just that you have an { } for the body of the destructor. [See Edit2 below!]
For example, if you have a vector or std::string, or whatever other class that needs destruction, in your baseclass, then you will leak the content of that class. In other words, you need to make 100% sure that the destructor of the baseclass is empty. I don't know of a programmatic way to determine that (beyond analysing the generated code, that is).
Edit:
Also beware of "changes in the future" - for example, adding a string or vector inside Base or changing the base class from Base to SomethingInheritedFromBase that has a destructor "with content" will ruin the "empty destructor" concept.
Edit2:
It should be noted that for the "destructor is empty", you have to have true empty destuctors in all derived clases too. There are classes that have no members that need destruction (interface classes typically have no data members, for example, so would not need destruction in themselves), so you could construct such a case, but again, we have to be VERY careful to avoid the destructor of a derived class adding a destructor into the class.

Does a C++ destructor always or only sometimes call data member destructors?

I'm trying to validate my understanding of C++ destructors.
I've read many times that C++ supplies a default destructor if I don't write one myself. But does this mean that if I DO write a destructor that the compiler WON'T still provide the default cleanup of stack-allocated class fields?
My hunch is that the only sane behavior would be that all class fields are destroyed no matter what, whether I provide my own destructor or not. In which case the statement I've read so many times is actually a little misleading and could be better stated as:
"Whether or not you write your own destructor, the C++ compiler always
writes a default destructor-like sequence to deallocate the member
variables of your class. You may then specify additional
deallocations or other tasks as needed by defining your own destructor"
Is this correct?
When an object is cleaned up in C++, the language will
First call the destructor for the class, then
Call the destructors for all the fields of the class.
(This assumes no inheritance; if there's inheritance, the base class is then destroyed by recursively following this same procedure). Consequently, the destructor code that you write is just custom cleanup code that you'd like to do in addition to the normal cleanup code for individual data members. You won't somehow "lose" the destructors for those objects being called as normal.
Hope this helps!
Yes -- any object contained within your object will be destroyed as part of destroying your object, even if/though your destructor does nothing to destroy them.
In fact, your destructor won't normally do anything to destroy objects contained within the object; what it typically does is destroy objects that are remotely owned via something in the object (e.g., a pointer to an object, a handle to a network or database connection, etc.)
The only exception to this that's common at all is if your object contains a buffer of some sort, and you've used placement new to construct something into that buffer. If you use placement new, you normally plan on directly invoking the dtor as well. [Note that "common" is probably overstating how often you see/use this--it's really quite uncommon, but the other possibilities are much rarer still.]
Yes. Even if you DO write a destructor, the C++ compiler will create a sequence. Consider the following code:
class foo{
int a;
}
Write a destructor that deallocates a, a stack-allocated variable... its impossible. Therefore, even if you write your own destructor, a C++ compiler MUST generate one to deallocate stack objects.

Deleting an object polymorphically

Base* optr=new Derived();
delete optr;
I know that if Base class has a non-virtual destructor, only ~Base() destructor is going to be called when deleting optr pointer. But I found out that even without ~Derived() destructor being called the memory that was taken by the Derived Object was freed. So my question is can an object get freed without calling it's destructor?
If the answer is yes, can I use a non-virtual destructor if my Derived class does not contain any dynamically allocated variables so I don't care if it did not get called?
From the viewpoint of standard C++, the answer is simple: the result is undefined behavior, so what you get is completely unpredictable
I'm a little puzzled why you'd care anyway. If you can eliminate all the virtual functions from a class, each instance becomes smaller (by the size of a vtable pointer). Using such a thing as a base class rarely makes sense though -- for use as a base class to be sensible, you pretty much need to have at least one virtual function in the base for the derived class to override. Once you have a virtual function (any virtual function) adding more is essentially free -- objects don't grow any larger by adding more virtual functions.
To answer your question directly: yes, the memory can be freed without the destructor being invoked. The real question is what will happen when you make that happen (and there's really no answer to that question).
The thing about undefined behaviour is that sometimes it seems to work.
The standard doesn't say that your program must fail if the base class destructor is not virtual, it says that it must work when the destructor is virtual.
You might be able to get away without a virtual destructor if the derived class doesn't add any members. The memory footprints will be the same, and the members will all be destroyed in the base class destructor. However this is not guaranteed by the standard and you'll be at the mercy of your compiler's implementation.
There're two distinct things: calling object destructor, and freeing the memory.
Standard heap specification does not require you to pass the memory block size when you free it. That is, the heap implementation should deduce the memory block size itself.
Hence - yes. If you Derived does not contain extra things that must be destroyed by appropriate means (such as memory allocated on heap, file handles and etc.) - you don't need the virtual destructor.
Look over here : Virtual destructor

virtual destructor's practical necessity in a particular case

C++03 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.
This is the theory. The question, however, is a practical one. What if the derived class adds no data members?
struct Base{
//some members
//no virtual functions, no virtual destructor
};
struct Derived:Base{
//no more data members
//possibly some more nonvirtual member functions
};
int main(){
Base* p = new Derived;
delete p; //UB according to the quote above
}
The question: is there any existing implementation on which this would really be dangerous?
If so, could you please describe how the internals are implemented in that implementation which makes this code crash/leak or whatever? I beg you to believe, I swear that I have no intentions to rely on this behavior :)
One example is if you provide a custom operator new in struct Derived. Obviously calling wrong operator delete will likely produce devastating results.
I know of no implementation on which the above would be dangerous, and I think it unlikely that there ever will be such an implementation.
Here's why:
"undefined behaviour" is a catch-all phrase meaning (as everyone knows), anything could happen. The code could eat your lunch, or do nothing at all.
However, compiler writers are sane people, and there's a difference between undefined behaviour at compile-time, and undefined behaviour at run-time. If I was writing a compiler for an implementation where the code snippet above was dangerous, it would be easy to catch and prevent at compile time. I can says it's a compilation error (or warning, maybe): Error 666: Cannot derive from class with non-virtual destructor.
I think I'm allowed to do that, because the compiler's behaviour in this case is not defined by the standard.
I can't answer for specific compilers, you'd have to ask the compiler writers. Even if a compiler works now, it might not do so in the next version so I would not rely on it.
Do you need this behaviour?
Let me guess that
You want to be able to have a base class pointer without seeing the derived class and
Not have a v-table in Base and
Be able to clean up in the base class pointer.
If those are your requirements it is possible to do, with boost::shared_ptr or your own adaptation.
At the point you pass the pointer you pass in a boost::shared_ptr with an actual "Derived" underneath. When it is deleted it will use the destructor that was created when the pointer was created which uses the correct delete. You should probably give Base a protected destructor though to be safe.
Note that there still is a v-table but it is in the shared pointer deleter base not in the class itself.
To create your own adaptation, if you use boost::function and boost::bind you don't need a v-table at all. You just get your boost::bind to wrap the underlying Derived* and the function calls delete on it.
In your particular case, where you do not have any data member declared in the derived class and if you do not have any custom new/delete operators (as mentioned by Sharptooth), you may not have any problems ,but do you guarantee that no user will ever derive your class? If you do not make your Base's destructor virtual, there is no way for any of the classes derived from Derived to call their destructors in case the objects of derived classes are used via a Base pointer.
Also, there is a general notion that if you have virtual functions in your base class, the destructor should be made virtual. So better not surprise anybody :)
I totally agree with 'Roddy'.
Unless you're writing the code for perverted compiler designed for a non-existing virtual machine just to prove that so-called undefined behavior can bite - there's no problem.
The point of 'sharptooth' about custom new/delete operators is inapplicable here. Because virtual d'tor and won't solve in any way the problem he/she describes.
However it's a good point though. It means that the model where you provide a virtual d'tor and by such enable the polymorphic object creating/deletion is defective by design.
A more correct design is to equip such objects with a virtual function that does two things at once: call its (correct) destructor, and also free its memory the way it should be freed. In simple words - destroy the object by the appropriate means, which are known for the object itself.

Class destructor memory handling in C++

What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
Thanks
vectors and the like will deallocate themselves because their destructor is called.
In fact your problem will lie with anything that would cause a problem of a dangling pointer (or handle or whatever), ie anything that needs to be manually Closed or de-allocated won't be in an implicit destructor. Anything that destructs itself properly will be fine. This is why the RAII idiom is so popular :)
I think the question is upside-down. Don't think in terms of what object destruction doesn't do: think in terms of what it does do.
If a class only has an implicit destructor, then when it is destroyed, all non-static data members are destroyed too, as are all base-class sub-objects.
You can argue a bit whether this is done "by the implicit destructor" or not - if you write a destructor, those things still happen. It's part of the object destruction process itself, rather than part of the code of the destructor as such.
So, if your "connection to a file" is a FILE* class member, then the default destructor doesn't release it, because FILE* is a C thing, and it doesn't have a destructor. Destroying a FILE* does nothing. If your "connection to a file" is a std::ofstream, then it does have a destructor, and the destructor tries to flush and close the connection.
Vector has a destructor which release the vector's resources. This means that in turn the elements in the vector have their destructors called.
For each member variable you have, you should look at the corresponding documentation to see how resources are handled for that type. Obviously with experience, you start to remember the answers.
If the member variable is a pointer, then the implicit destructor doesn't do anything with it. So if it points to heap-allocated memory, and this object holds the only pointer to that memory, then you need to free it to avoid a memory leak.
If you find yourself writing a destructor in C++ that needs to free more than one thing, then you've probably designed the class badly. There are almost certainly exception-safety errors elsewhere in the class: it's possible to get the code right, but if you're experienced enough to get it right then you're experienced enough to make your own life easier by designing it differently ;-). The solution is to write classes with a single responsibility -- to manage a single resource -- and use them as member variables. Or, better, to find library classes that manage the resource you're using. shared_ptr is pretty flexible.
"need you destroy non-heap variables"
There is no such thing in C++ as "heap" and "non-heap" variables. Destroying a pointer does not free the thing pointed to, for the obvious reason that nothing in the type of a pointer tells you how the thing it points to was allocated, or who "owns" it.
You need to understand three things about destructors. Say you have an object t of class T with three members.
class T
{
A a;
B b;
C c;
// ...
} t;
Destructing t ALWAYS means calling the following destructors in that order: ~T(), ~C(), ~B(), ~A(). You cannot influence these semantics. It is impossible to prevent the destruction of the members. This ALWAYS happens, no matter if you define ~T() manually or if the compiler generates it.
Implicitly generated destructors are ALWAYS a no-op. However, as stated in point 1, the destructors ~C(), ~B() and ~A() will still be executed afterwards.
The destructors of scalar types, especially C-style pointers, are ALWAYS a no-op. This is the sole reason why you almost always need to write the destructor (and the copy constructor and the assignment operator) manually when you have a C-style pointer member -- after ~T() has finished, destructing a C-style pointer member does NOTHING, so any cleanup intended on the pointees has to be done in ~T().
I hope this clears things up for you.
What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
To put it simply, you are correct. The only thing not handled by the implicit destructor is memory allocated in the form of a pointer or another type of resource that needs to be released explicitly.
With regard to vectors or any other class type objects; all classes have a destructor which takes care of releasing their data. The destructor of an object of this type is called when it goes out of scope. All basic data types like: int, float, double, short, bool etc are released in similar fashion.
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
The answer to this is that they are handled automatically, in fact you should never ever try to explicitly call the destructor of an object.
In an implicit destructor the following occurs:
Each of the member variables of the class have their destructors called in turn.
In an explicit destructor the following occurs:
The body of the explicit destructor is executed
Each of the member variables of the class have their destructors called in turn.
So you can see that an explicit destructor is much the same as an implicit one, except that you can take any necessary manual intervention.
Now as a bit of advice with regard to managing memory allocated objects you should pretty much always use RAII (resource acquisition is initialisation). The crux of this is smart pointers, these are pointers that are deleted correctly when they go out of scope just like non heap allocated objects. Ownership becomes an issue once you start using them but that's a story for another day. A good place to start with smart pointers is boost::shared_ptr. (btw if you haven't got on board with boost yet and you write c++ code do yourself a favour...)
The implicit destructor calls the destructor on all member variables.
If you have a raw pointer, its destructor does nothing. So if you own the memory it points to, you have to release it explicitly.
The same applies to any other resource, or any other action you wish to take not implied by the default destructor of the member variable.
The default destructors of members are still called, so vectors, auto_ptrs, files opened using std streams or other C++ libraries all get destroyed. The moral is to wrap any OS objects which need releasing in C++ classes which tidy themselves up, so that application classes don't have to worry about it.
A class' destructor will implicitely call the destructors of all non-static members, then the destructors of virtual base classes, then its own code.
If you have STL containers as class members, you don't have to do anything explicitely--they will free their own memory in their destructors.
You're already making wrong assumptions. If my class holds heap-allocated data using an std::auto_ptr<Data>, the implicit dtor will handle it. No memory will be leaked. The reason is that the implict dtor, like any other dtor, will call the dtors of all members and base classes.
Now, a good class design holds all important resources as members with proper dtors. As a result, the dtor body needs to do nothing to prevent resource leaks. Of course, there is one exception to that rule: resource managing classes themselves manage precisely one resource, and therefore clean up that one resource in their dtor.