Was reading Wikipedia for RAII when just saw Single
and Shared
ownership.
Googled for it and couldn't find any useful answer!
Could some one possibly explain this concept for a schoolboy?
Was reading Wikipedia for RAII when just saw Single
and Shared
ownership.
Googled for it and couldn't find any useful answer!
Could some one possibly explain this concept for a schoolboy?
It is essentially unique_ptr
vs shared_ptr
.
Single ownership, otherwise known as unique ownership, means that the resource is owned by a single class instance. Once that instance ceases to exist the resource is released (via the destructor). The majority of RAII classes you find have unique ownership, such as std::vector
.
Shared ownership means the resource is shared between multiple class instances. The resource is only released once every instance ceases to exist and thus requires some form of reference counting or garbage collection. An example of where you would want shared ownership is a handle to a very expensive to copy immutable resource. I've seen it used in graphs too.
It might help to think in terms of pointers. Single ownership will only have 1 owning pointer, shared will have multiple. Of course, RAII might not involve pointers.
+---------------+
|Shared instance|
+--------+ +------------+--+ +---------------+
|Resource| | +----------+Shared instance|
+--------+ v v +---------------+
^ +--------+
| |Resource|<-----------+
| +--------+ +---+-----------+
| ^ |Shared instance|
+------+--------+ | +---------------+
|Unique Instance| |
+---------------+ |
+------+--------+
|Shared instance|
+---------------+
Ownership is strongly tied with the concept of variable lifetimes.
If you can answer the question, when is it ok for this chunk of memory to go away?, then you can answer the issue of ownership.
If that chunk of memory is only tied with the lifetime of one variable, then you have single ownership.
Note that it's also important to think about heap or dynamic allocation vs stack or automatic variables. With automatic variables, when they go out of scope, the memory associated with them are reaped. With dynamic allocation, the same is not true, in the general case. If you use new facilities like std::unique_ptr<> for single ownership, then you can make a chunk of dynamic memory clean itself up when it falls out of scope. If there are many references to that chunk of memory with uncertain ordering of when the references will go away, then you may need something like a std::shared_ptr<> for multiple ownership.
Ownership boils down to who is responsible for freeing a resource. Usually, you can say that one portion of code (be it a function, or a class) is the only owner of a resource. When it is done with the resource, the owner will have to free it for the resource not to leak. This is known as single or unique ownership.
Likewise, there exists a concept of shared ownership where two or more discrete portions of code, once again they could be classes or functions, both count on the same resource. In this case, both must no longer have any need for the resource before it can be freed.
C++ provides two helpful wrappers to convey and enforce ownership semantics -- ownership semantics being what is described above. These wrappers genericize the concept of RAII -- the automatic freeing of a resource once it has gone out of scope.
unique_ptr
-- An object wrapped in a unique pointer will be freed immediately when it goes out of scope, meaning the function returns or the class is destroyed.
shared_ptr
-- An object wrapped in a shared pointer will remain available until all "strong references" are gone out of scope. This is a concept known as reference counting. Once the final reference goes out of scope, the resource is freed.
Ownership semantics are incredibly important in a language such as C++ so I recommend you get acquainted with how modern C++ conveys and enforces it. You can started by learning the correct usage of unique_ptr
and shared_ptr
.
In relation to smart pointers / raii, shared ownership is when more than one object can reference the same resource, and this resource is only released when all instances of that object referencing the resource are deconstructed.
// shared ownership
{
std::shared_ptr<SomeClass> i(new SomeClass());
{
std::shared_ptr<SomeClass> j = i;
{
std::shared_ptr<SomeClass> k = j;
// at this point i, j, k all own the same object
}
// k deconstructed and no longer shares ownership of the resource
}
// j deconstructed and no longer shares ownership of the resource
}
// i deconstructed and he resource is also released / free'd
With shared (unique) ownership either dies with the object, or is passed to the other object
// single/unique ownership
{
std::unique_ptr<SomeClass> i(new SomeClass());
{
std::unique_ptr<SomeClass> j = std::move(i); // k takes ownership of the object from i
}
// j is deconstructed and the resource is also released / free'd
}
// i deconstructed and nothing is released, as the ownership already passed to j
Single ownership means that when the owner has finished with a resource, it should delete it.
If it's shared ownership, then, it can't delete it because the other owner(s) might still be using it! Thus, the resource deletion must be coordinated via some means, typically by reference counting.