Re: [boost] Review Request: Generalization of the Pimpl idiom

For that syntax to work with a hierarchy every class needs to explicitly declare a constructor taking "implementation*". That is, in the following hierarchy Base : pimpl<Base> {} Derived1 : public Base {} Derived2 : public Derived {} pimpl, Base and Derived1 need to have those mentioned constructors so that the following could work Derived2::Derived2(int) : Derived1(new Derived2Implementation()) { } That requirement to have Derived1::Derived1(implementation*) is unreasonable as it is clearly not related to to the Derived1 *public* interface. On the other hand reset()-based approach works fine and scales fine. ... the
I am not sure what that is supposed to demonstrate. You use infrastructure to help you to do your job. If you decide that the infrastructuere does not help you and discard that, you'll obviously have to re-implement whatever functionality from that infrastructure you managed to deploy. If one uses std::list and then for whatever reason goes ahead with his own list implementation or merely swaps it for std::vector, he'll likely to face the same issue. Trade-offs of the pimpl idiom are well-known -- another indirection and memory allocation. In the end, one can deal with memory-allocation by writing a custom allocator for pimpl<Foo>::implementation.
I cannot say about you but I do really think that the pimpl idiom is helping me to hide the implementation. Private inheritance restricts access but not hides the implementation. struct Base { int k; }; class Derived : Base {} Here Base::k is not accessible in Derived but not hidden. More, if that stuff is a commercial library, I can easily circumvent that restriction by modifying Derived declaration. Pimpl really hides the implementation. See for more about the idiom 1. Guru of the Week #24. http://www.gotw.ca/gotw/024.htm 2. Herb Sutter. Exceptional C++ (Addison-Wesley, 1999) 3. J. Carolan. Constructing bullet-proof classes. In Proceedings C++ at Work'89 (SIGS Publications, 1989) 4. James O. Coplien. Advanced C++ Programming Styles and Idioms (Addison-Wesley, 1992) 5. Eric Gamma et al. Design Patterns (Addison-Wesley,1995) ...
Once we remove the public inheritance from pimpl, it is not eassy to implement all these extra functions and operators.
for B implementation does not seem to have much value. Having said
Then do not remove public inheritance. I am far from being convinced that insistence on private inheritance is justified. ... that that,
It depends. Even if it does, it'll be truly just a bit.
It feels like you want two separate hierarchies -- for interface and implementation. The application of the Pimpl idiom to polymorphic class hierarchies is well described in the "Bridge" section of GoF. the
complete inheritance hierarchy.
I am not sure how relevant it is to the technical side of things. We are not in a legal profession where for legal reasons they write "may contain traces of nuts" on a packet of nuts. I see infrastructure as providing a service. Decision about applicability of that service for a particular situation is application developer's responsibility. I dot thin the time of the infrastructure developer will be well spent trying to think of every situation where his code *cannot* be used.
Yes, I understand what you describe and 'no' I do not think it'll be an issue. And, no, again, in my view private inheritance does not help you one bit. (Just admit you like "her", don't you. :-) )
I cannot see anything drastically wrong with the code above even though I probably would not do it that way. So, I'll have to disagree with your conclusion. pointer_semantics.
No, it does not. I am overwhelmingly using pimpl::pointer_semantics and those are happily in various containers. And those objects behave polymorphically because they have pointer semantics. If it is not the desired behavior, then value_semantics should be used instead. It is up to the class designer to decide. protect
Well, I probably can agree with this conclusion... although I am temped to argue that in that case we'll have to put similar "warnings" everywhere. Like "do not use knife when you actually need a spoon", etc.
In order to understand better your purpose: * Could you give an example in which the object has value semantics and
the
Private implementation does not have any particula semantics. It is the interface (pimpl-derived) class who has pointer_ or value_semantics... meaning how it treats the implementation -- aloows to share it or copies it.
pimpl. pain.
I have to disagee as I find that view over-simplified and in fact incorrect. Pimpl or no pimpl in general no objects beyond value-semantics PODs can be safely (or without additional effort) put into shared memory. the
implementation of A. What I can do?
Shared memory is a delicate area. It's like embedded programming where not all language resources are readily available. If your A class can live in shared memory, then it is essentially a POD. Say, consisting of a few integers, no pointers, no inheritance. Otherwise, two processes cannot access/manipulate that same object in shared memory (not easily anyway). Still, those processes must have access synchronization issues resolved. More so, you mention a container in shared memory. Is it a standard container? Then, you'll have to provide custom allocators. The issue just keeps more and more complicated. Do you actually have that setting or we are talking hypothetically? If the former, then pimpl will not be your primary concern. :-) If it is the latter, then I find it too ephemeral to discuss effectively. If you do not have several processes accessing the same data and, therefore, do not care for inter-process data-access synchronization, inter-process vtbl pointer correction, etc., then I'd be wondering why you use shared memory in the first place.
Well, again I am not sure we should rush with conclusions based purely on hypothetical assumptions without trying. I admit I did not try using pimpl with shared memory as I do not use shared memory these days. It's almost not portable, limiting, hard to handle, and most (all?) of the time is better implemented as a multi-threaded app anyway.
really
adequated.
Well, I certainly biased :-) but I am trying to keep an open mind and so far I do not see anything that I'd consider as a limitation. Call me a stubborn nut if you like. ...
I consider value- or pointer-semantics to be the behavior when null() is clearly a functionality. They are very much orthogonal to each other. Foo::null() clearly declares an invalid (unusable) object regardles of its semantics. I see value in it. If one does not need that functionality, he probably won't use it. As simple as that. I did not hear compellling arguments *not" to provide that functionality for value-semantics classes. Thanks, Vladimir.

Hi Vladimir, ----- Original Message ----- From: <Vladimir.Batov@wrsa.com.au> Subject: Re: [boost] Review Request: Generalization of the Pimpl idiom
I understand now. This will force to add an artifial *protected* constructor to Derived1. Do you really think that this is a real problem for the developer of Derived1? If I understand your library forbids this to the developper because pimpl_base do not have the following protected constructor. pimpl_base (implementation* impl) : impl_(impl) {} I think that this will be a good adding to the pimpl_base class.
If pimpl is here to hide the implementation, why it needs to extends the interface of the initial class? Why the user of my class should suffer from the trade-offs of the pimpl idiom at the inteface level?
I was talking about private inheritance from pimpl!!!
This is why I suggested to remove the null object and bool type conversion operators for pimpl<A>::value_semantics. Maybe it will be a good idea to give them protected acces.
Conveinced or not this is a way to mask the pimpl functions, and it seams to me the best way to use pimpl<A>::value_semantics. This is not the case with pimpl<A>::pointer_semantics from which it is better to inherit publically giving acces to the null object and the bool type conversion operators. This is only a comment on how I will use it :-)
Sorry, but in this use case I can not change A.
In any case I don't see a real benefit of using pimpl when the base class is 3pp class and we can not change it.
Anyway, we will do the same, don't use pimpl with multiple inheritance.
OK, it is clear now.
Sorry for the tautology
I hope so, and I expect that you will do what is needed to achiev this. I tried only to help you.
Pointers are emulated in Boost.Interprocess with the smart pointer offet_prt. You can yet have inheritance without virtual functions. Otherwise, two processes cannot
Please, could you take a look to the Boost.Interprocess, Boost.Intrusive and Boost.MultiIndex libraries. Even if not standards they are portable. :-)
I insist. This is not hypothesis. I have to manage a lot of data shared between process, I use specific allocators, and synchronization mechanisms. I wanted only to know if I can hide the implementation of this classes with the pilm classes. That's all.
Who has said that I have no several process sharing the same data? But the data has no virtual functions. This is not a raison to don't want to hide its implementation.
Without trying I know that the way you use the pointers do not allow to put your class is shared memory. You can see offset_ptr in Boost.Interprocess.
Doesn't matter, I understand your concern.
It was only an idea :-)
Thanks, Vladimir.
Thank you very much for your time and good luck for your review. I promise I'll try your library. _____________________ Vicente Juan Botet Escriba
participants (2)
-
vicente.botet
-
Vladimir.Batov@wrsa.com.au