Unique and shared ownership

Unique ownership and shared ownership are design patterns very common in C++. Yet, I was not able to find any place where they would be clearly described. So here we go. The two concepts describe the two different relations of objects that we use in the program to the resources that they own. In short, shared ownership indicates that many different objects may own the very same resource; unique ownership indicates that a given resource may only be owned by one object.


We will be talking a lot about resources in this post, so we deserve a decent definition of the term. A resource, for the purpose of our post, is something in the system that we will need, and that we will likely be short of, and that other parts of program or other programs will likely also need. The most interesting part is that we will share resources with others therefore it is essential to be very clear when and for how long we will use them in order not to interfere with others that also will use our resource. In order to achieve this we introduce the concept of acquiring the ownership of the resource — henceforth we owe the resource, we can use it and noöne else; and of releasing the ownership of the resource — henceforth we will not use it anymore and anyone else can acquire the ownership of the resource. Typically, when giving an example of such a resource we mention memory or a mutex (for inter-thread synchronisation). This is because they are most typical, widely known, and platform independent resources. However, we can think of any more: any device in your system is a resource.

Resource acquisition and release in C++

C++ provides very handy tools for acquiring and releasing resources. First, a deterministic object life-time; that is, for every object it is exactly defined upon which moment its life-time will end. Upon this moment a destructor will be called, and it can be used for automatic resource release. Note that this is not possible in garbage-collected languages, because there it is not known when the object’s life-time will end. It may not even end at all. Second, the way constructors and destructors inter-operate with exception mechanism. When a constructor of a given object o succeeds, its destructor is scheduled to be called regardless if the program proceeds normally, or if an exception is thrown, or if the ‘outer class’s’ (o is sub-object of) constructor fails, or if some other destructor throws in between. This, if we use objects with automatic storage duration, makes a constructor a perfect tool for resource acquisition, and a destructor — for resource release, because we are sure that resources that any function acquires will be released even if the function fails to do its job. It also guarantees that if a given function cannot acquire a given resource, it will release all resources it already acquired. Third, in case a number of objects is declared in the same scope (block, function scope, class scope), destructors of objects are called in the inverse order than that in which their constructors were called. This can often be used to quickly detect resource conflicts and avoid deadlocks, if you think of mutexes as resources.

Using constructors of resource acquisition and destructors for resource release is a well known design pattern in C++ and is called Resource Acquisition Is Initialisation, or more popularly, RAII.

Scoped resource ownership

So, the basic, most often sufficient, and the safest method for implementing a resource management is to have an object in the program represent a resource: one object — one resource. The way to implement it is to acquire the resource in our object’s constructor, release the resource in our object’s destructor, and disable both copy constructor and copy assignment. A typical usage of thus designed a class will typically look as follows.

    Adapter adapter;  // acquire the adapter
}   // implicitly release the adapter

Technically, object adapter does not represent the adapter resource, but the exclusive ownership of the adapter, which we obtained for a certain amount of time. If we need to pass adapter to other functions, like doThat, we need to do it by reference because we do not want to have two copies of adapter: they would represent two ownerships, but the two object lifetimes are different (although partially overlapping). It would cause interpretations of the ownership difficult to reason about.

The above concept of ownership is often called a guard in C++. Hence the name std::lock_guard in C++11.

Move semantics

While the above passing argument by reference is clear and generally accepted, there exists a problem, how to return an object representing a resource from a function. For instance, you may want to have a factory function that creates an object and returns it to the caller, who in turn uses the object. Returning by value in C++03 requires the usage of copy constructor, and we already out-ruled any copying because we do not want to have two copies of the same object holding the same resource. However, in case of a factory function the situation is different. Imagine the following factory function:

File openFile( string name ) {
    string path = getPath();
    string ext = getExtension();
    return Flie( path + name + ext ); 

It is not possible that we would have two copies. We only create a temporary object that we do not intend to use ourselves; we just want to pass the resource further to the caller. Often this problem is solved in practise by creating File object on the free store (heap) and returning it by a (preferably smart) pointer. This solution has certain drawbacks: using pointers (even smart ones) makes the program less readable, and creating objects on the free store is often far more expensive than using automatic objects. There is a solution to the problem of pointers and the free store: you need to detect the situations where copying is not really copying but handing over the object to someone else, and apply different copying logic in that case, that doesn’t really copy, but ‘steals’ the content of the original object, leaving it empty. This is called move semantics. We do not have enough room to describe this concept, but it has been well described by many authors (see here and here). In short, this is how it works. You need your object to be able to store a null state, a valid state of the object where it does not own a resource. For instance, a default constructed std::auto_ptr is in a null state: it does not own any memory that it should be deleting. Second, you need to detect the situations where the copying is really handing the resource over (moving). It turns out to be fairly easy: when you copy from a temporary (an r-value) it is certainly a move; otherwise, when you copy from a normal object with a name (an l-value), it is a copy. Is it easy to detect when we are copying from a temporary? There are already libraries to do that, see Boost.Move. In C++11 you have a simpler solution: there is a second type of reference (an r-value reference) that binds to temporaries and takes precedence over the regular (const) reference. You can define a copy and a move constructor:

struct Type 
    Type( Type const& ); // copy constructor
    Type( Type && );     // move constructor 

In move constructor you just make a shallow copy of the original, and set the original into a null state. That’s it. For resource classes you would disable the copy constructor and leave only the move constructor working. Move construction allows you to pass objects representing resources by value and still guarantee the unique ownership of the resource. A similar technique has been used to implement std:auto_ptr: you can return it by value, but you cannot just copy it.

Shared resource ownership

Occasionally, the point at which the resource is no longer needed and can be released cannot be easily determined because a number of different parts of the program use it, and it is not known which part will finish using the resource last. For instance consider flyweight pattern, or a situation where two threads use the common memory to communicate with one another; we do not know which thread will finish first, but the one that finishes second needs to make sure memory is released. This is the room for shared resource ownership pattern. You can copy objects that own resources. Such a copy is shallow: all objects represent the very same resource. The resource is released by the object that is destroyed last. This requires reference counting or a similar technique for keeping track of who is the last owner. The most famous implementation of this technique in C++ is shared_ptr originally from Boost, now also in tr1 and C++11.

Personally, I have never found a convincing use case for shared ownership. Typically, the program can be designed in ‘scoped’ manner, where it is always clear who is responsible for which resource and up to which point. On the other hand, I have often seen an incorrect usage of shared ownership. Some people that switch from garbage-collected languages, sometimes consider shared_ptr a C++ implementation of a garbage collector: they allocate memory on free store whenever they need a new object and just assign it to shared_ptrs. This leads to an unclear code, and occasionally, memory leaks.

Some examples

For the end, let’s have a look at a couple of types from C++03, C++11 and Boost, to see which model of resource ownership they implement. Usually the name of the type suggests the answer. Types that implement scoped ownership:

  • std::lock_guard — this C++11 type represents a scoped ownership of the mutex,
  • boost::scoped_ptr — in this case a memory (allocated with operator new) is a resource; the type provides no move semantics,
  • std::istream, std::ostream — resource is a data stream,

Types that provide full unique ownership (with move semantics):

  • std::auto_ptr — resource is memory,
  • std::unique_lock — a C++11 type for owning a mutex,
  • std::thread — a C++11 type for owning a thread of program execution,
  • std::fstream, std::stringstream — resource is a file / string buffer.

Types that provide shared ownership :

  • std::shared_ptr, boost::shared_ptr,
  • std::shared_future — a C++11 type for owning a future result of a function that is being concurrently executed by another thread.
This entry was posted in programming and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.