Go back to Richel Bilderbeek's homepage.
Go back to Richel Bilderbeek's C++ page.
This is the answer of exercise #1: a foolproof function.
We do not want to modify a Thing. The compiler, however, does not know this. The compiler thinks we do want to modify a Thing, because the pointer to Thing is not const. This makes it possible to write to a Thing, as shown in the code below:
struct Thing { int mX; }; |
To solve this problem, make Thing const:
struct Thing { int mX; }; |
Use const whenever possible [1-4].
Before being read, pointers must always point to a valid object. Nothing prevents us from making the pointer-to-Thing point to zero:
struct Thing { int mX; }; |
To solve this problem, make the pointer itself const as well. This brings you to the following code:
struct Thing { int mX; }; |
Again, use const whenever possible [1-4].
Be aware that you can delete a pointer-to-const. Deleting a Thing, however, is disastrous:
struct Thing { int mX; }; |
To solve this problem, we must modify Thing itself.
struct Thing |
Now, exercise #1: a foolproof function has succeeded. If you knew all three steps, you get an A. Congratulations!
But...
A new problem has arisen: we cannot construct a Thing, as it cannot be deleted when going out of scope:
struct Thing |
Try to solve this problem yourself. Make it work. But keep ReadThing foolproof.
Got it?
Already?
Are you sure?
Okay, I'll show the solutions.
The way to solve this problem is to use the friend keyword. I show three possible friends:
'What, use friend?', I hear you mutter, 'You should never use friend!', as well as 'friend reduces encapsulation!'. If you just muttered these words, feel free to contact me with a reference to the book in which you read this. I could not find it anywhere in my literature collection.
And also, if you muttered this, read the following three options below to see that there is more encapsulation, instead of less: Thing cannot be destroyed by anything, except its only, single friend. This makes Thing more encapsulated than by making everything able to destroy it. Read it again: making Thing destructable by its only, single friend only, makes Thing more encapsulated by making everything able to destroy it.
struct Thing |
Befriending the main function has its restrictions: a Thing cannot be a class member. For this simple piece of code, however, it is a valid solution.
#include <memory> |
A std::auto_ptr calls the destructor of Thing when it goes out of scope. So, when making a std::auto_ptr a friend of Thing, you can create std::auto_ptr<Thing>.
A drawback of this solution is that a std::auto_ptr does not have a checked delete (for example boost::checked_delete).
#include <boost/shared_ptr.hpp> |
My personal favorite solution. But also this solution has a drawback, as one can now write the following in ReadThing:
void ReadThing(const Thing * const thing) |
But the exercise was to make ReadThing foolproof, not evil-genius-proof.
The ReadThing function has one assumption: the pointer must point to a valid Thing. Use assert to document internal assumptions [5-9].
#include <cassert> |
Again, use assert to document internal assumptions [5-9].
Go back to Richel Bilderbeek's C++ page.
Go back to Richel Bilderbeek's homepage.