
2010/12/14 Vladimir Batov <vbatov@people.net.au>
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.
You are right, I misunderstood the definition of pimpl_base. I thought it was being specialized outside of pimpl, but it is not the case. template<class T> struct pimpl /// Generalization of the Pimpl idiom { struct implementation; template<class> class impl_ptr; template<template<class> class> class pimpl_base; /// Convenience typedef to deploy pimpl with value semantics. typedef pimpl_base<impl_ptr> value_semantics; /// Convenience typedef to deploy pimpl with pointer semantics. typedef pimpl_base<boost::shared_ptr> pointer_semantics; }; So pimpl_base can accept as its template parameter only a template that takes one argument, like shared_ptr. But it cannot take a template with two or more parameters, correct? Why not just do the following? template < class SmartPtr > class pimpl_base; Another question: what is the purpose of Your pimpl struct? In other words, assuming pimpl_base takes a regular template parameter, what is the advantage of class MyClass : pimpl<MyClass>::pointer_semantics; over class MyClass : pimpl_base< shared_ptr<MyClassImpl> >; 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 admit "any" is not the right word for what I had in mind. I ment some smart pointer, that the author of the pimpl<> template does not know of; that smart pointer may not yet exist. Since You place typedefs inside pimpl (value_semantics, pointer_semantics), I presume You intend to predict all possible used spart pointers. Otherwise usage would be something like: class MyClass : pimpl<MyClass>::pimpl_base<MySmartPtr>; whereas MySmartPtr would have to be a template with one template argument. ...
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.
I can't find it
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.
I disagree. Make_shared is provided separatly from shared_ptr, and must be used instead of operator new, when creating an object.
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.
A constructor from pimpl_base: pimpl_base() : impl_(new implementation()) {} It creates implementation using operator new. I was suggesting adding a factory parameter to pimpl, and delegating creating to the factory, instead of explicitly calling new implementation()
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.
I think we don't understand each other on the definigion of "user". Earlier I proposed to call a user someone who uses MyClass, and to call an implementer someone, who implements MyClass and optionally uses pimpl. When You say "user deploying [pimpl] pattern/idiom", You must mean the implementer. However, if You don't think hiding the use of pimpl from the user is a good thing, then I guess we just have different oppinions about it. 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.
I see, so we disagree on this. I don't think exposing operator bool_type is part of the idiom. I think we did not agree on the definition of pimpl, and I think this leads to all the other things we disagree upon ;-) [...] 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,
Good luck and all the best to You too, Kris