To add to my previous email, the reason we cannot use Owned there is because it's a public mesos header, and we don't wanna introduce extra dependency to libprocess for frameworks.
On Mon, Dec 15, 2014 at 10:15 AM, Dominic Hamon <[email protected]> wrote: > > I think that's a good use, though I think using emplace_back would be a > better move when dealing with unique_ptr, assuming we have it in 4.4? > > On Fri, Dec 12, 2014 at 9:25 PM, Jie Yu <[email protected]> wrote: > > > > Good start Dominic! I have another example which I think using unique_ptr > > is preferred. > > > > We need to store a vector of pointers to the base class (which means we > > have to use pointers here). However, storing raw pointer makes the > > ownership tracking not explicit. What do you guys think? > > > > // Base class. > > class Transformation > > { > > public: > > virtual ~Transformation() {} > > > > virtual Try<Resources> apply(const Resources& resources) = 0; > > }; > > > > // Derived class. Use composite pattern. > > class CompositeTransformation : public Transformation > > { > > public: > > CompositeTransformation() {} > > > > * void add(std::unique_ptr<Transformation> transformation)* > > * { * > > * transformations.push_back(std::move(transformation));* > > * } * > > > > virtual Try<Resources> apply(const Resources& resources); > > > > private: > > *std::vector<std::unique_ptr<Transformation>> transformations;* > > }; > > > > On Fri, Dec 12, 2014 at 3:01 PM, Dominic Hamon > <[email protected] > > > > > wrote: > > > > > > Great idea. > > > > > > There is one place that immediately springs to mind that I think is > > trivial > > > but will get us used to the idea and exercise some of the demons: Unit > > > tests. Within a test we regularly create some object on the heap and > then > > > delete it at the end of the test, or for the lifetime of a test > fixture. > > > All of these should be well scoped in lifetime and are prime targets > for > > > unique_ptr. > > > > > > On Wed, Dec 10, 2014 at 3:32 PM, Jie Yu <[email protected]> wrote: > > > > > > > > Dominic, > > > > > > > > Thank you for brining this up! Instead of making a decision based on > > high > > > > level design and coding philosophy, I would really love to see some > > > > concrete examples in our code base where we can start to use > unique_ptr > > > and > > > > why it's better. Thoughts? > > > > > > > > - Jie > > > > > > > > On Wed, Dec 10, 2014 at 3:20 PM, Dominic Hamon < > > [email protected]> > > > > wrote: > > > > > > > > > Hello! > > > > > > > > > > We have access to std::unique_ptr, as many of you know, but we're > not > > > > using > > > > > it. I'd like to start using it. Before we do, I'd like to discuss > how > > > we > > > > > use it, when we use it, and things to be aware of. > > > > > > > > > > The style guide has the following to say (long quote, sorry): > > > > > > > > > > " > > > > > Prefer to have single, fixed owners for dynamically allocated > > objects. > > > > > Prefer to transfer ownership with smart pointers. > > > > > > > > > > "Ownership" is a bookkeeping technique for managing dynamically > > > allocated > > > > > memory (and other resources). The owner of a dynamically allocated > > > object > > > > > is an object or function that is responsible for ensuring that it > is > > > > > deleted when no longer needed. Ownership can sometimes be shared, > in > > > > which > > > > > case the last owner is typically responsible for deleting it. Even > > when > > > > > ownership is not shared, it can be transferred from one piece of > code > > > to > > > > > another. > > > > > > > > > > "Smart" pointers are classes that act like pointers, e.g. by > > > overloading > > > > > the * and -> operators. Some smart pointer types can be used to > > > automate > > > > > ownership bookkeeping, to ensure these responsibilities are met. > > > > > std::unique_ptr is a smart pointer type introduced in C++11, which > > > > > expresses exclusive ownership of a dynamically allocated object; > the > > > > object > > > > > is deleted when the std::unique_ptr goes out of scope. It cannot be > > > > copied, > > > > > but can be moved to represent ownership transfer. std::shared_ptr > is > > a > > > > > smart pointer type that expresses shared ownership of a dynamically > > > > > allocated object. std::shared_ptrs can be copied; ownership of the > > > object > > > > > is shared among all copies, and the object is deleted when the last > > > > > std::shared_ptr is destroyed. > > > > > > > > > > It's virtually impossible to manage dynamically allocated memory > > > without > > > > > some sort of ownership logic. > > > > > Transferring ownership of an object can be cheaper than copying it > > (if > > > > > copying it is even possible). > > > > > Transferring ownership can be simpler than 'borrowing' a pointer or > > > > > reference, because it reduces the need to coordinate the lifetime > of > > > the > > > > > object between the two users. > > > > > Smart pointers can improve readability by making ownership logic > > > > explicit, > > > > > self-documenting, and unambiguous. > > > > > Smart pointers can eliminate manual ownership bookkeeping, > > simplifying > > > > the > > > > > code and ruling out large classes of errors. > > > > > For const objects, shared ownership can be a simple and efficient > > > > > alternative to deep copying. > > > > > Ownership must be represented and transferred via pointers (whether > > > smart > > > > > or plain). Pointer semantics are more complicated than value > > semantics, > > > > > especially in APIs: you have to worry not just about ownership, but > > > also > > > > > aliasing, lifetime, and mutability, among other issues. > > > > > The performance costs of value semantics are often overestimated, > so > > > the > > > > > performance benefits of ownership transfer might not justify the > > > > > readability and complexity costs. > > > > > APIs that transfer ownership force their clients into a single > memory > > > > > management model. > > > > > Code using smart pointers is less explicit about where the resource > > > > > releases take place. > > > > > std::unique_ptr expresses ownership transfer using C++11's move > > > > semantics, > > > > > which are relatively new and may confuse some programmers. > > > > > Shared ownership can be a tempting alternative to careful ownership > > > > design, > > > > > obfuscating the design of a system. > > > > > Shared ownership requires explicit bookkeeping at run-time, which > can > > > be > > > > > costly. > > > > > In some cases (e.g. cyclic references), objects with shared > ownership > > > may > > > > > never be deleted. > > > > > Smart pointers are not perfect substitutes for plain pointers. > > > > > If dynamic allocation is necessary, prefer to keep ownership with > the > > > > code > > > > > that allocated it. If other code needs access to the object, > consider > > > > > passing it a copy, or passing a pointer or reference without > > > transferring > > > > > ownership. Prefer to use std::unique_ptr to make ownership transfer > > > > > explicit. For example: > > > > > > > > > > std::unique_ptr<Foo> FooFactory(); > > > > > void FooConsumer(std::unique_ptr<Foo> ptr); > > > > > Do not design your code to use shared ownership without a very good > > > > reason. > > > > > One such reason is to avoid expensive copy operations, but you > should > > > > only > > > > > do this if the performance benefits are significant, and the > > underlying > > > > > object is immutable (i.e. std::shared_ptr<const Foo>). If you do > use > > > > shared > > > > > ownership, prefer to use std::shared_ptr. > > > > > > > > > > Do not use scoped_ptr in new code unless you need to be compatible > > with > > > > > older versions of C++. Never use std::auto_ptr. Instead, use > > > > > std::unique_ptr. > > > > > " > > > > > > > > > > Now I'm a big fan of explicit ownership and moving ownership rather > > > than > > > > > sharing non-smart pointers, but I recognise that in our code-base, > > > > > ownership is difficult to reason about in many cases. However, we > do > > > have > > > > > quite a few cases where we manage lifetime scope with explicit > delete > > > > calls > > > > > and I'd like to start by eliminating those. Ie, using > std::unique_ptr > > > to > > > > > manage lifetime not necessarily ownership. > > > > > > > > > > This is difficult though as we may pass these pointers to other > > methods > > > > or > > > > > even other libprocess processes. In cases that we can reason about > > the > > > > > lifetime of the various pointers, that should be fine, but we have > to > > > be > > > > > careful. > > > > > > > > > > One option is to start by replacing these pointers with > > process::Owned. > > > > The > > > > > downside to this approach is that it introduces more non-standard > > types > > > > > and, because Owned is implemented using std::shared_ptr, doesn't > move > > > us > > > > > closer to defining clear ownership. > > > > > > > > > > So the floor is open. Do we: > > > > > > > > > > 1) embrace std::unique_ptr, eliminate raw pointers except in rare, > > > > > well-defined cases from a lifetime point of view? > > > > > 2) eliminate raw pointers in favour of std::shared_ptr and > > > > std::unique_ptr > > > > > then work to eliminate the std::shared_ptrs > > > > > 3) use process::Owned everywhere and then find places where we can > > > > > transition them to std::unique_ptr > > > > > 4) do nothing; there's no great benefit to std::unique_ptr and this > > > smart > > > > > pointer thing is just a fad. > > > > > > > > > > > > > > > - dominic > > > > > > > > > > > > > > > -- > > > > > Dominic Hamon | @mrdo | Twitter > > > > > *There are no bad ideas; only good ideas that go horribly wrong.* > > > > > > > > > > > > > > > > > > -- > > > Dominic Hamon | @mrdo | Twitter > > > *There are no bad ideas; only good ideas that go horribly wrong.* > > > > > > > > -- > Dominic Hamon | @mrdo | Twitter > *There are no bad ideas; only good ideas that go horribly wrong.* >
