Skip to main content
added 411 characters in body
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }

         // Note: Default constructor
         //       Uses the default initialization values.
         my_shared_ptr() {}

         // Take ownership of a pointer.
         explicit my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         // You may want a constructor that takes a `nullptr`
         // Because the above will not allow nullptr because of
         // the explicit
         my_shared_ptr(std::nullptr_t)
             : ptr(nullptr)
             , size(nullptr)
         {}

         // Standard Copy Constructor.
         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }

         // Standard Move Constructor
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
             // as original objects pointers have been set to null
             // Thus effectively transferring ownership of any
             // pointer.
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         explicit my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         // You may want a constructor that takes a `nullptr`
         // Because the above will not allow nullptr because of
         // the explicit
         my_shared_ptr(std::nullptr_t)
             : ptr(nullptr)
             , size(nullptr)
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }

         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }

         // Note: Default constructor
         //       Uses the default initialization values.
         my_shared_ptr() {}

         // Take ownership of a pointer.
         explicit my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         // You may want a constructor that takes a `nullptr`
         // Because the above will not allow nullptr because of
         // the explicit
         my_shared_ptr(std::nullptr_t)
             : ptr(nullptr)
             , size(nullptr)
         {}

         // Standard Copy Constructor.
         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }

         // Standard Move Constructor
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
             // as original objects pointers have been set to null
             // Thus effectively transferring ownership of any
             // pointer.
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
added 307 characters in body
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         explicit my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         // You may want a constructor that takes a `nullptr`
         // Because the above will not allow nullptr because of
         // the explicit
         my_shared_ptr(std::nullptr_t)
             : ptr(nullptr)
             , size(nullptr)
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
 
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         explicit my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         // You may want a constructor that takes a `nullptr`
         // Because the above will not allow nullptr because of
         // the explicit
         my_shared_ptr(std::nullptr_t)
             : ptr(nullptr)
             , size(nullptr)
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
 
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }


         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object
                                                 // into a temp. This will be
                                                 // destroyed at end of scope
                                                 // and thus reduce the counter
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
deleted 1 character in body
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }
 

         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destoyeddestroyed (which maywill not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object 
 in a temp.
                                              // into a temp. This will be
                                                 // destroyed at end of scope 
 and thus
                                               // and thus reduce the counter 
 if there is one.
             my_shared_ptr old{std::move(*this)};                               // if there is one.


             // Do the work.
             // The current object is now null
             // soSo we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the currentnew value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};    // increment of any counters
                                         // happens in the copy.
                                         // decrement of any counters
                                         // happens when this object
                                         // is destoyed (which may not
                                         // be the same as the object created :-)
             tmp.swap(*this);
             return *this;
         }
     
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             // This moves the current object in a temp.
             // This will be destroyed at end of scope and thus
             // reduce the counter if there is one.
             my_shared_ptr old{std::move(*this)};

             // The current object is now null
             // so we swap with the source thus putting nulls
             // into "move" and setting this object with the current value.
             move.swap(*this);
             return *this;
         }

         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
template<typename T>
class my_shared_ptr
{
     T            ptr   = nullptr;
     std::size_t* size  = nullptr;


     bool decrementCountReachedZero() const
     {
         --(*size);
         return *size == 0;
     }

     public:
         ~my_shared_ptr()
         {
             if (size && decrementCountReachedZero()) {
                 delete ptr;
                 delete size;
             }
         }
         my_shared_ptr() {}

         my_shared_ptr(T* take)
             : ptr(take)
             , size(new std::size_t{1})
         {}

         my_shared_ptr(my_shared_ptr const& copy)
             : ptr(copy.ptr)
             , size(copy.size)
         {
             // OK we have constructed now.
             // So increment the size if it exists
             if (size) {
                ++(*size);
             }
         }
         my_shared_ptr(my_shared_ptr&& move) noexcept
             : ptr(std::exchange(move.ptr, nullptr))
             , size(std::exchange(move.size, nullptr))
         {
             // No action required
         }
 

         // NOTE HERE
         //
         // I am writing both the copy and move assignment
         // operators out in full. This is NOT the best way
         // to do it. I am doing this to help illustrate the
         // correct way. (See below)

         // For normal copy assignment.
         // Use the copy and swap idiom.
         my_shared_ptr& operator=(my_shared_ptr const& copy)
         {
             my_shared_ptr tmp{copy};            // increment of any counters
                                                 // happens in the copy.
                                                 // decrement of any counters
                                                 // happens when this object
                                                 // is destroyed (which will not
                                                 // be the same as the object created :-)

             // Do the work.
             // Swap the tmp and the current object.
             // everything should be in the correct place.
             tmp.swap(*this);
             return *this;
         }
     
         // For normal move assignment.
         // Make sure the current object owned by "this" is destroyed.
         // Overwrite "this" one and set "move" old version to nullptr.
         my_shared_ptr& operator=(my_shared_ptr&& move) noexcept
         {
             my_shared_ptr tmp{std::move(*this)};// This moves the current object 
                                                 // into a temp. This will be
                                                 // destroyed at end of scope 
                                                 // and thus reduce the counter 
                                                 // if there is one.


             // Do the work.
             // The current object is now null
             // So we swap with the source("move") thus putting nulls
             // into "move" and setting this object with the new value.
             move.swap(*this);
             return *this;
         }

         // NOTE: You will notice that both versions of
         //       the assignment operator are identical.
         // So there is a neat trick to simplify both these
         // into a single assignment operator that handles
         // both situations:

         // Simply pass by value.
         // If it is an lvalue it is copied.
         // If it is an rvalue it will be moved.
         // Which has the identical operation as the tmp variable
         my_shared_ptr& operator=(my_shared_ptr tmp) noexcept
         {
             tmp.swap(*this);
             return *this;
         }
         // At this point tmp goes out of scope.
         // destroying the tmp copy or the old value
        


         // Utility function.
         void swap(my_shared_ptr& other) noexcept
         {
             std::swap(ptr,  other.ptr);
             std::swap(size, other.size);
         }
         friend void swap(my_shared_ptr& lhs, my_shared_ptr& rhs)
         {
              lhs.swap(rhs);
         }
};
deleted 1 character in body
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
Loading
added 449 characters in body
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
Loading
Source Link
Loki Astari
  • 97.9k
  • 5
  • 126
  • 342
Loading