In an earlier article, we have seen how move constructor & move assignment operators helped us in creating our own unique_ptr
. Here we will use move constructor & assignment operator to implement unsophisticated shared_ptr.
Implementing Our shared_ptr with Move Constructor & Assignment Operator
- In some cases, we have a requirement where a single resource is represented by multiple pointers. We can not accomplish this by
std::unique_ptr
. To accomplish this, we can add a new variable to our smart pointer class which keeps track of reference count at the real-time. And when the reference count goes to zero which means nobody is using that resource, we will deallocate that resource. - Unlike
std::unique_ptr
, which is designed to singly own and manage a resource,std::shared_ptr
is meant to solve the case where you need multiple smart pointers co-owning a resource.
|
|
- Unlike
std::unique_ptr
, which uses a single pointer internally,std::shared_ptr
uses two pointers internally. One pointer points at the managed resource. The other points at a “control block”, which is a dynamically allocated object that tracks of a bunch of stuff, including how manystd::shared_ptr
are pointing at the resource. - Here I have only used a single variable to keep track of references pointing to resource for simplicity. The actual implementation is a bit bulky for more feature & security purpose.
A bit about move constructor & move assignment operator
When does the move constructor & move assignment operator get called?
The move constructor and move assignment are called when those functions have been defined, and the argument for construction or assignment is an r-value
. Most typically, this r-value
will be a literal or temporary value.
- In most cases, a move constructor and move assignment operator will not be provided by default, unless the class does not have any defined copy constructors, copy assignment, move assignment, or destructors. However, the default move constructor and move assignment do the same thing as the default copy constructor and copy assignment (make copies, not do moves).
l-value
reference & r-value
reference
- I have already written a separate article for that.
std::move
- In C++11,
std::move
is a standard library function that serves a single purpose – to convert its argument into anr-value
. - Once you start using move semantics more regularly, you’ll start to find cases where you want to invoke move semantics, but the objects you have to work with are
l-values
, notr-values
.
Use case or benefit of std::move
- Consider the following
swap()
function as an example:
- Above
swap()
function makes 3 copies. That leads to a lot of excessive string creation and destruction, which is slow. - However, doing copies isn’t necessary here. All we’re really trying to do is swap the values of
a
andb
, which can be accomplished just as well using 3 moves instead! So if we switch from copy semantics to move semantics, we can make our code more performant.
std::move
can also be useful when sorting an array of elements. Many sorting algorithms (such as selection sort and bubble sort) work by swapping pairs of elements. Here we can use move semantics, which is more efficient.