Making a smart pointer which works with incomplete types
I asked a long time ago in this group how to make a smart pointer
which works with incomplete types. I got this answer (only relevant
parts included):
//------------------------------------------------------------------
template<typename Data_t>
class SmartPointer
{
Data_t* data;
void(*deleterFunc)(Data_t*);
static void deleter(Data_t* d) { delete d; }
void decrementReferenceCount()
{
if(data)
{
// decrement reference count and then:
if(<reference count == 0>)
{
deleterFunc(data);
}
}
}
public:
SmartPointer(Data_t* d): data(d), deleterFunc(&deleter) {}
~SmartPointer() { decrementReferenceCount(); }
// etc...
};
//------------------------------------------------------------------
When done like this, the template type must be complete only when the
smart pointer is constructed. It doesn't need to be complete when it's
destructed, copied or assigned.
What bothered me back then is that the pointer to the deleter function
is a member variable of the class, increasing its size. What is worse,
all the smart pointer instances of the same type will have the exact
same function pointer as member variable, which feels like a huge waste.
Then it occurred to me: Is there any reason this pointer cannot be
static? Like this:
//------------------------------------------------------------------
template<typename Data_t>
class SmartPointer
{
....
static void(*deleterFunc)(Data_t*);
....
public:
SmartPointer(Data_t* d): data(d)
{
deleterFunc = &deleter;
}
....
};
template<typename Data_t>
void(*SmartPointer<Data_t>::deleterFunc)(Data_t*) = 0;
//------------------------------------------------------------------
This way the pointer to the deleter will be stored in the program only
once, and most importantly it will not increment the size of the smart
pointer.
This feels so glaringly obvious to me now that I really wonder why
this wasn't suggested to me to begin with. Is there some error here I'm
missing?
(It might seem hazardous to have the function pointer initialized to
null, as it might happen that the decremetReferenceCount() function
might in some situations make a call to that null pointer. However,
whenever there is something in the 'data' pointer, the deleter function
pointer will always have been initialized. It's no different in this
regard as having the function pointer as a member variable.)