C++ Forcing a certain storage for your objects and 'delete this'
Forcing a certain storage for your objects
Originally posted at http://www.ciprian-miclaus.com/tips/enforce.asp?tip=b&id=3 (editted formatting)In general we don't care if our classes get instantiated on the stack or on the free store (the storage where new/delete allocate memory vs. heap which is used to denote the storage used malloc/free). But there are cases when we would like our classes to be instantiated only on the stack or only on the free store. Why would we want something like this? Let's say we end up with a pointer to an object which we own. Should we or should we not delete it? If the object is on the free store and we do not delete it, we end up with memory leaks. However, if the object is on the stack and we're trying to delete it, we'll obviously end up with a splendid crash.
As a rule of thumb, whoever creates an object should destroy it too, so the whole thing about where it was created is generally not a problem. However, there are cases when parameters are passed asynchronously and they're usually created on one side and destroying something else, maybe in different threads. Then usually we'll want to allocate parameters on the free store. But we'll also want to enforce that they should be allocated only on the free store as one might allocate them on the stack and the parameters might be destroyed by the creating-end before they're examimded by the other end.
So, such enforcements of the storage used by certain classes are not totally futile. Let's see how can we enforce in C++ that a class should be instantiated only on the stack or only on the free store. This is about how and where objects are created. So we're probably want to take a look at areas like constructors, destructors, operator new, operator delete, copy constructor, because those are the places where an object of a certain type gets constructed. We also have the access specifiers: public, protected, private. By playing with these toys, we should achieve our purpose.
Forbidding a class to be instantiated on the free store is simple. Just make the operator new and delete protected or private, and client code will not be able to call them, so they will be enforced to instantiate it on the stack.
class OnlyOnStack {
public:
//constructor
OnlyOnStack ();
//destructor
~OnlyOnStack ();
//..public interface here
private:
operator new (size_t) {}
operator delete (void*) {}
};
Forbidding a class to be instantiated on the stack seems simple too. If we simple make the constructors protected or private, we will not be able to instantiate it on the stack. Simple enough. Not quite. When a class gets instantiated on the free store, two things happens:
then the global operator new is used) that allocates memory for the object
2. the constructor is called
class OnlyOnFreeStore {
public:
//constructor
OnlyOnStack ();
//..public interface here
private:
//destructor
~OnlyOnStack ();
};
If we try to instantiate it on the stack with a simple:
OnlyOnFreeStore trivialInstance;
OnlyOnFreeStore* pOnlyOnFreeStore = new OnlyOnFreeStore;
delete pOnlyOnFreeStore;
Well, what happens is: 1. Compiler calls the destructor to destruct the object
2. Compiler calls operator delete the memory allocated for the object
class OnlyOnFreeStore {
public:
//constructor
OnlyOnStack ();
DeleteThis () {
delete this;
}
//..public interface here
private:
//destructor
~OnlyOnStack ();
};
OnlyOnFreeStore* pOnlyOnFreeStore = new OnlyOnFreeStore;
//...use the object here
pOnlyOnFreeStore->DeleteThis ();
//the object is destroyed
Mission accomplished...
<< Home