
From: "Krzysztof Czainski" <1czajnik@gmail.com> Sent: Friday, December 10, 2010 12:06 AM ...
template<class T> struct pimpl { typedef pimpl_base<impl_ptr> value_semantics; typedef pimpl_base<boost::shared_ptr> pointer_semantics; typedef pimpl_base<cow_ptr> cow_semantics; };
Isn't it "customization of the copying policy"? Or did you mean something else?
I see. But if I understand correctly, for each smart pointer type, there needs to be a specialization of pimpl_base written from scratch.
I am not sure where you've got that impression from. There is one pimpl_base implementation. Pointer- or value-semantics behavior are defined by the provided policy class. Pls see the declaration above.
Now suppose pimpl_base<SmartPtr> does accept any smart pointer: scoped_ptr, shared_ptr, clone_ptr, cow_ptr, etc... This is where the creation policy is needed. See below...
I do not immediately see value in Pimpl accepting "any smart pointer" which are policy classes for Pimpl. In fact, I do not know of any policy-based class which would accept *any* other class as its policy. I am convinced a class to be used as a policy by another class must conform to a certain interface.
...
I am under impression that I do not quite understand what you mean by "customization of the creating policy" either. Isn't that quality achieved by overloaded constructors? If it is so, then the developer provides the set of overloaded constructors for his/her class. Regardsless of those constructors Pimpl does not need to be modified.
The default creation policy would be to create impl on the heap using operator new, and passing the resulting pointer to SmartPtr. But for example, when using shared_ptr, it might be a good idea to use a) make_shared instead of operator new, b) a custom allocator/deleter.
I am under impression that the functionality you are suggesting is already available. Namely, (unless I am still missing your point) "make_shared" quality is provided by boost::shared_ptr itself and nothing more needs to be done. As for "custom allocator/deleter" or any other creation policy, then that functionality belongs in the "implementation" class and deployed via Pimpl interface. So, it seems nothing more needs to be done in Pimpl either.
3. The user should have no way of telling if MyClass uses pimpl or not. It should be totally transparent.
I happen to disagree. Pimpl implements a certain pattern/idiom which has certain qualities. The user deploying that pattern/idiom expects those qualities. After all, that's why he/she is deploying that pattern/idiom in the first place. I do not immediately see benefits of hiding those qualities.
Well, I understand You expose the operator bool_type for example.
Again, I believe it is part of the idiom. For example, boost::shared_ptr is similar in that regard.
But that is not all. I believe a user is also someone deriving form MyClass. Your pimpl takes part in runtime polymprphism, and for that it must be visible by derived classes.
Again, Pimpl is implementation of a certain programming technique. Consequently, one can certainly inherit from a Pimpl (and I do it a lot) but without negating Pimpl's property and ultimately the object size. It's done via the Bridge pattern (as in GoF). Essentially, the developer has two separate inheritance hierarchies -- for interface and for implementation. I believe I have it covered in the documentation.
... I just thought that, since the user should not know of pimpl's existence, there should be no functions to inherit from it.
I see no value in encapsulation for the sake of encapsulation. Say, you can "typedef boost::shared_ptr<Foo> Zoo;" or go further trying to hide the fact that Zoo is, in fact, a shared_ptr and, consequently behaves as a shared_ptr. By trying to hide that fact I believe you do the user great disservice as you deny the user the knowledge that Zoo has certain qualities/properties (namely, shared_ptr properties) as *must* be treated as such.
...
As for your concern about "a lot of operations" in Pimpl "potentially conflicting with operators" of YourClass, then my reading of the specification is somewhat different. Namely, as I understand, a method introduced in the derived class makes *all* the methods with the same name (not just the same signature) in the base class inaccessible.
True. So, what if the implementer adds operators * and -> to MyClass? Accessing pimpl is still possible, but not as convenient any more. satic_cast<implementation&>(*this)->... or an extra local reference is always needed:
Therefore, if I understand you correctly you are suggesting to remove those operators altogether, right? ;-) More so, there is no need for the user to add operators * and -> as Pimpl provides already those operators for him/her.
For the pointer_semantics-based Pimpl: I do not think that MyClass should have pointer semantics just because its pimpl has pointer semantics. So I am against forwarding op== from the underlying shared_ptr.
I am not sure I follow -- you deploy pointer-semantics Pimpl but do not want it to behave as such. I have that feeling you are trying to make things harder than they need be. In my simple world, if I deploy a fork, I do want it to "behave" as a fork, i.e. to expose fork-like properties. If I don't, I'll deploy something else.
I just think virtual functions should just stay in MyClass, and not go into pimpl, because they should not be hidden. That is why I think "pimpl should have nothing to do with polymorphism" ;-)
I do not believe the proposed Pimpl implementation has any virtual functions. As described in the documentation it's deployed in the inheritance hierarchies differently (the Bridge pattern in GoF).
For an example of how I use pimpl, and my pimpl helper, which I called value_ptr, I shall quote my earlier post, adding an example of how some member function of MyClass might be implemented in terms of pimpl:
I am sure your Pimpl implementation does everything just the way you want it. :-) And if that works better for you than an already available component, then I do not see anything wrong with deploying it. I do the same all the time. ;-) Still, I suspect if you try deploying your no-frills version of a larger scale, it'll start looking more and more as the proposed Pimpl. There are countless examples of that behavioral pattern (Java comes to mind). As for the proposed Pimpl, let me assure you that the functionality provided and described there is there for a reason. May I suggest you have another look at the documentation for the proposed Pimpl? You might come to appreciate its versatility... or might not. :-) Good luck and all the best in your endeavors, V.