Application code doesn't need to invoke move (and probably shouldn't). In the examples, I think it's more of an exercise to show what would happen if invoked. And really, I expect same badness to happen using shared pointer method if we dereferenced a moved pointer.
Thanks, David On Mon, Sep 18, 2017 at 11:19 AM, Mark Hanson <mhan...@pivotal.io> wrote: > If you think this is a significant ease of use benefit, why have to invoke > move? I understand this code, but I have not seen it in recent memory. > I agree that this may make use of a copy(move) constructor easier, but... > > If the consensus is that this is a significant ease of use benefit for the > user, I am on board… > > +1 > > Thanks, > Mark > > On Sep 18, 2017, at 11:15 AM, David Kimura <dkim...@pivotal.io> wrote: > > > > The benefit I see isn't for performance, it's flexibility and ease of use > > by application developer. Anything we can do to achieve this, I think > is a > > significant win. > > > > I think the reason for the various approaches is to determine whether we > > can safely create the simple/flexible API without incurring a penalty on > > performance. Personally, I think the no nullptr benefit that Sarge > > mentioned in previous thread is enough to warrant this approach serious > > thought even though it provides no performance benefit. > > > > Thanks, > > David > > > > On Mon, Sep 18, 2017 at 10:47 AM, Mark Hanson <mhan...@pivotal.io> > wrote: > > > >> Hi All, > >> > >> As we are creating a user API, unless there is a significant performance > >> benefit, I think we should try to take the simpler route. > >> > >> I see benefit to the approach being proposed, but I don’t see a > >> significant benefit. Someone please school me if I am wrong. > >> > >> I am still in the shared pointer camp for cache and a raw pointer to > cache > >> in cacheImpl. > >> > >> Sorry, and thanks, > >> Mark > >> > >> > >> > >>> On Sep 18, 2017, at 10:14 AM, David Kimura <dkim...@pivotal.io> wrote: > >>> > >>> +1 value approach (via some implementation from this thread) > >>> > >>> I think I like this. > >>> > >>> In all BAD cases, it's the user who shot themselves in the foot by > using > >>> std::move unsafely. I expect this behavior is the same behavior as for > >> any > >>> other object. And if we're ever able to get rid of the Cache/CacheImpl > >>> circular dependency then we can add a copy constructor. > >>> > >>> I also like the idea of passing in a CacheConfig. My concern though is > >>> that it's piling on another big change. > >>> > >>> Thanks, > >>> David > >>> > >>> On Sun, Sep 17, 2017 at 12:02 AM, Jacob Barrett <jbarr...@pivotal.io> > >> wrote: > >>> > >>>> Ok, one more idea. > >>>> https://gist.github.com/pivotal-jbarrett/ > beed5f70c1f3a238cef94832b13dab > >> 7a > >>>> > >>>> The biggest issue with the value model is that we have been using a > >> factory > >>>> to build the Cache object. We really don't need one and if we get rid > >> of it > >>>> things look much better. They aren't perfect since we still need the > >> back > >>>> pointer from the impl to the cache for later use. If we didn't need > that > >>>> then we could allow copy construction. As it stands right now this > >> version > >>>> allows value, shared_prt, unique_ptr, etc. without any real overhead > or > >> RVO > >>>> issues. > >>>> > >>>> The big change is that, rather than have a factory that we set a bunch > >> of > >>>> values on and then ask it to create the Cache, we create a CacheConfig > >>>> object and pass that in to the Cache's constructor. Cache passes it to > >>>> CacheImpl and CacheImpl sets itself up based on the config. If you > look > >> at > >>>> what the current factory model does it isn't that different. For > >> clarity I > >>>> added an XmlCacheConfig object to that builds up the CacheConfig via > >> Xml. > >>>> You could imagine a YamlCacheConfig object *shiver*. The point is we > >> don't > >>>> care as long as we get a CacheConfig with all the things we support at > >>>> "init" time. > >>>> > >>>> I know it is a more radical change but I feel it is more C++ and more > >>>> testable than the factory model. I also like that it solves some of > the > >>>> issues with the value model we were looking at. > >>>> > >>>> -Jake > >>>> > >>>> On Thu, Sep 14, 2017 at 5:16 PM Jacob Barrett <jbarr...@pivotal.io> > >> wrote: > >>>> > >>>>> Y'all here is an attempt to get the best of both worlds. > >>>>> https://gist.github.com/pivotal-jbarrett/ > >> 52ba9ec5de0b494368d1c5282ef188 > >>>> ef > >>>>> > >>>>> I thought I would try posting to Gist but so far not impressed, > sorry. > >>>>> > >>>>> The Gist of it is that we can overcome the thirdpary or transient > >>>>> reference back to the public Cache instance by keeping a reference to > >> it > >>>> in > >>>>> the implementation instance and updating it whenever the move > >> constructor > >>>>> is called. > >>>>> > >>>>> The downside is if your run this test it doesn't show RVO kicking in > on > >>>>> the second test where we move the value into a shared pointer. There > >> are > >>>> a > >>>>> couple of pitfalls you can stumble into as well by trying to used the > >>>>> previous instance to access the cache after the move operation, as > >>>>> illustrated by the "BAD" commented lines. > >>>>> > >>>>> The upside is the choices this gives the use for ownership of their > >>>>> factory constructed Cache instance. They can keep it a value or move > it > >>>> to > >>>>> unique or shared pointer. > >>>>> > >>>>> Overhead wise I think we better off in value as long as there are no > >>>>> moves, rare I would thing, but the moves are pretty cheap at the > point > >>>>> since we only maintain a unique_ptr. After moving into a shared_ptr > it > >>>> acts > >>>>> identical to the shared_ptr model proposed earlier. > >>>>> > >>>>> -Jake > >>>>> > >>>>> > >>>>> On Thu, Sep 14, 2017 at 3:36 PM Michael Martell <mmart...@pivotal.io > > > >>>>> wrote: > >>>>> > >>>>>> Late to this party. > >>>>>> > >>>>>> Confession 1: I had to look up both RVO and copy-elision. > >>>>>> Confession 2: I don't like using pointers at all. I used to, but > I've > >>>>>> evolved to just use C# and Java :) > >>>>>> > >>>>>> Without investing a lot more time, I don't have strong feelings > about > >>>> raw > >>>>>> vs shared pointers. My only question is: Can we return ptr to > abstract > >>>>>> class everywhere we return objects? Just thinking of mocking, which > >>>> always > >>>>>> wants to mock interfaces. > >>>>>> > >>>>>> On Thu, Sep 14, 2017 at 2:25 PM, Michael William Dodge < > >>>> mdo...@pivotal.io > >>>>>>> > >>>>>> wrote: > >>>>>> > >>>>>>> +0 shared pointer > >>>>>>> > >>>>>>>> On 14 Sep, 2017, at 14:09, Ernest Burghardt < > eburgha...@pivotal.io> > >>>>>>> wrote: > >>>>>>>> > >>>>>>>> Calling a vote for: > >>>>>>>> > >>>>>>>> - Raw pointer > >>>>>>>> - shard pointer > >>>>>>>> > >>>>>>>> +1 raw Pointer, I had to look up RVO and am new to std::move(s) > >>>>>>>> > >>>>>>>> On Thu, Sep 14, 2017 at 3:02 PM, Michael William Dodge < > >>>>>>> mdo...@pivotal.io> > >>>>>>>> wrote: > >>>>>>>> > >>>>>>>>> I generally dig reference-counted pointers for avoiding lifetime > >>>>>> issues > >>>>>>>>> with objects allocated off the heap but I can live with bare > >>>>>> pointers, > >>>>>>> too. > >>>>>>>>> > >>>>>>>>> Sarge > >>>>>>>>> > >>>>>>>>>> On 13 Sep, 2017, at 16:25, Mark Hanson <mhan...@pivotal.io> > >>>> wrote: > >>>>>>>>>> > >>>>>>>>>> Hi All, > >>>>>>>>>> > >>>>>>>>>> I favor the “pointer" approach that is identified in the code > >>>>>> sample. > >>>>>>>>> There is greater clarity and less bytes seemingly created and > >>>>>> written. > >>>>>>> We > >>>>>>>>> do sacrifice the potential ease of using an object, but in all, I > >>>>>> think > >>>>>>> the > >>>>>>>>> way our code is structured. It is not conducive to do a value > >>>>>> approach, > >>>>>>>>> from an efficiency standpoint, because of our use of the pimpl > >>>>>> model. > >>>>>>>>>> > >>>>>>>>>> Thanks, > >>>>>>>>>> Mark > >>>>>>>>>> > >>>>>>>>>>> On Sep 12, 2017, at 11:09 AM, Jacob Barrett < > jbarr...@pivotal.io > >>>>> > >>>>>>>>> wrote: > >>>>>>>>>>> > >>>>>>>>>>> My biggest concern with this model is that access to the public > >>>>>> Cache > >>>>>>>>>>> object from other public objects results in additional > >>>> allocations > >>>>>> of > >>>>>>> a > >>>>>>>>>>> Cache value. Think about when we are inside a Serializable > object > >>>>>> and > >>>>>>> we > >>>>>>>>>>> access the Cache from DataOutput. > >>>>>>>>>>> > >>>>>>>>>>> As value: > >>>>>>>>>>> Serializable* MyClass::fromData(DataInput& dataInput) { > >>>>>>>>>>> auto cache = dataOutput.getCache(); > >>>>>>>>>>> ... > >>>>>>>>>>> } > >>>>>>>>>>> In this the value of cache will RVO the allocation of Cache in > >>>> the > >>>>>>>>> getCache > >>>>>>>>>>> call into the stack of this method, great. The problem is that > >>>>>> Cache > >>>>>>>>> must > >>>>>>>>>>> contain a std::shared_ptr<CacheImpl> which means that each > >>>>>> allocation > >>>>>>>>> is 8 > >>>>>>>>>>> bytes (pointer to control block and pointer to CacheImpl) as > well > >>>>>> as > >>>>>>>>> having > >>>>>>>>>>> to increment the strong counter in the control block. On > >>>>>> exit/descope, > >>>>>>>>> the > >>>>>>>>>>> Cache will have to decrement the control block as well. > >>>>>>>>>>> > >>>>>>>>>>> Using current shared_ptr pimple model: > >>>>>>>>>>> Serializable* MyClass::fromData(DataInput& dataInput) { > >>>>>>>>>>> auto& cache = dataOutput.getCache(); > >>>>>>>>>>> ... > >>>>>>>>>>> } > >>>>>>>>>>> We only suffer the ref allocation of 4 bytes and no ref count. > >>>>>> Since > >>>>>>>>> this > >>>>>>>>>>> function call can't survive past the lifespan of > Cache/CacheImpl > >>>>>> they > >>>>>>>>> don't > >>>>>>>>>>> need to have shared_ptr and refcounting. > >>>>>>>>>>> > >>>>>>>>>>> Given that this method could be called numerous times is the > >>>>>> overhead > >>>>>>> of > >>>>>>>>>>> the value version going to be a significant performance issue? > >>>>>>>>>>> > >>>>>>>>>>> I worry that moves and RVO is just beyond most developers. > Heck I > >>>>>>> didn't > >>>>>>>>>>> know anything about it until we started exploring it. > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> -Jake > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> On Tue, Sep 12, 2017 at 8:06 AM David Kimura < > dkim...@pivotal.io > >>>>> > >>>>>>>>> wrote: > >>>>>>>>>>> > >>>>>>>>>>>> Follow up of attached discussion after more investigation. I > >>>>>> created > >>>>>>>>> an > >>>>>>>>>>>> example of returning Cache as shared pointer versus raw value: > >>>>>>>>>>>> > >>>>>>>>>>>> https://github.com/dgkimura/geode-native-sandbox > >>>>>>>>>>>> > >>>>>>>>>>>> I still like returning by value as it lets the user do what > they > >>>>>> want > >>>>>>>>> with > >>>>>>>>>>>> their object. > >>>>>>>>>>>> > >>>>>>>>>>>> // Here user creates object on their stack. > >>>>>>>>>>>> auto c = CacheFactory::createFactory().create(); > >>>>>>>>>>>> > >>>>>>>>>>>> // Here user creates smart pointer in their heap. > >>>>>>>>>>>> auto cptr = > >>>>>>>>>>>> std::make_shared<Cache>(CacheFactory::createFactory(). > >>>> create()); > >>>>>>>>>>>> > >>>>>>>>>>>> Difficulty of implementing this is high due to circular > >>>>>> dependencies > >>>>>>> of > >>>>>>>>>>>> Cache/CacheImpl as well as objects hanging off CacheImpl that > >>>>>> return > >>>>>>>>>>>> Cache. We must be extra careful when dealing with move/copy > >>>>>>> semantics > >>>>>>>>> of > >>>>>>>>>>>> Cache/CacheImpl. > >>>>>>>>>>>> > >>>>>>>>>>>> Alternative, is to keep as is and only permit heap allocations > >>>>>> from > >>>>>>>>>>>> factory using shared pointers. > >>>>>>>>>>>> > >>>>>>>>>>>> Thanks, > >>>>>>>>>>>> David > >>>>>>>>>>>> > >>>>>>>>>> > >>>>>>>>> > >>>>>>>>> > >>>>>>> > >>>>>>> > >>>>>> > >>>>> > >>>> > >> > >> > >