Alf said:
* Juha Nieminen:
No, shared_ptr does not use a static pointer.
It uses a regular pointer, which is even worse.
Your whole point was that storing this pointer anywhere could be
avoided altogether.
There's no error-prone-ness: you can't do wrong.
So an additional requirement of "if you instantiate the smart pointer
in an environment where the type is complete, include this file, else
include this another file" is not error-prone?
With the boost::shared_ptr solution there's only one single include
file and no possibility of error.
Having to choose between different header files depending on whether
the type might be incomplete or not.
The simplest is to do exactly what you want to achieve,
telling the compiler exactly what that is.
That's not the simplest thing to do. The simplest thing is when you
*don't have to* tell the compiler about your special cases and instead
the compiler can deduce them itself automatically.
If having to do everything explicitly is the "simplest" thing to do,
then you should switch to C and forget about C++. There you won't have
to worry about the compiler or the libraries doing things for you
automatically.
Instead of introducing
roundabout detours via static pointers, which *is* complexity.
We are talking about complexity from the point of view of the user, in
other words, the complexity of the public interface of the class and its
requirements, ie. how complicated it is to use.
How complicated the private implementation of a class is, is
completely inconsequential as long as it causes the public interface to
be easy to use and safe, and preferably the class as efficient as possible.
From the computer's point of view one function pointer per used type
is nothing. It doesn't even require any significant amounts of memory.
Thus the implementation is very efficient with respect to memory
consumption.
Adding requirements to the public interface of the class (eg.
requiring the user to write additional lines) when there's no functional
or significant efficiency reasons to do so simply doesn't make sense.
I have trouble grasping why you're arguing for that pointer, given that
your question was how to get rid of it.
Where did you get this impression? I never said I want to get rid of
it. What I said is that I want to take it out of the smart pointer
object so that it doesn't increase its size.
Of course getting completely rid of it (without making the usage of
the smart pointer more complicated) would be cool, but it's technically
impossible. The simple fact is: If the object must be deletable by the
smart pointer in a context where the type is incomplete, the destructor
of the smart pointer cannot delete it directly, nor can it instantiate
any deleter function which does so.
This goal can be achieved by making the user create such a function
and giving it to the smart pointer. No matter how many tricks you try to
invent to automatize this as much as possible, it will always require
the user to explicitly write something extra. This is needlessly
burdensome and error-prone. It's needlessly so because it can be easily
avoided.
Another way of achieving this is by the smart pointer automatically
instantiating the deleter function itself. The only place where it can
do so (as per the specs) is in the constructor. After this the only way
the destructor can call this automatically generated function without
actually instantiating it itself as well, is through a function pointer.
There's no way of passing this function pointer from the constructor to
the destructor other than storing it somewhere.
This is the exact technique that boost::shared_ptr uses to
automatically support incomplete types.