Implementing a Smart Pointer Using Reference Counting

// CustomSmartPointer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;

/* Reference Count: A simple class for maanging the number of active smart pointers*/
class ReferenceCount
{
private:
  int m_RefCount{ 0 };
public:
  void Increment()
  {
    ++m_RefCount;
  }
  int Decrement()
  {
    return --m_RefCount;
  }
  int GetCount() const
  {
    return m_RefCount;
  }
};


template <typename T>
class smart_ptr
{
private:
  T* m_Object{ nullptr };
  ReferenceCount* m_ReferenceCount{ nullptr };
public:
  smart_ptr()
  {
  }
  //Constructor
  smart_ptr(T* object)
    : m_Object{ object }
    , m_ReferenceCount{ new ReferenceCount() }
  {
    m_ReferenceCount->Increment();
    cout << "Created smart_ptr! Ref count is " << m_ReferenceCount->GetCount() << endl;
  }

  //Destructor
  virtual ~smart_ptr()
  {
    if (m_ReferenceCount)
    {
      int decrementedCount = m_ReferenceCount->Decrement();
      cout << "Destroyed smart_ptr! Ref count is " << decrementedCount << endl;
      if (decrementedCount <= 0)
      {
        delete m_ReferenceCount;
        delete m_Object;

        m_ReferenceCount = nullptr;
        m_Object = nullptr;
      }
    }
  }

  // Copy Constructor
  smart_ptr(const smart_ptr<T>& other)
    : m_Object{ other.m_Object }
    , m_ReferenceCount{ other.m_ReferenceCount }
  {
    m_ReferenceCount->Increment();
    cout << "Copied smart_ptr! Ref count is "
      << m_ReferenceCount->GetCount() << endl;
  }

  // Overloaded Assignment Operator
  smart_ptr<T>& operator=(const smart_ptr<T>& other)
  {
    if (this != &other)
    {
      if (m_ReferenceCount && m_ReferenceCount->Decrement() == 0)
      {
        delete m_ReferenceCount;
        delete m_Object;
      }
      m_Object = other.m_Object;
      m_ReferenceCount = other.m_ReferenceCount;
      m_ReferenceCount->Increment();
    }
    cout << "Assigning smart_ptr! Ref count is " << m_ReferenceCount->GetCount() << endl;
    return *this;
  }

  //Dereference operator
  T& operator*()
  {
    return *m_Object;
  }

  //Member Access operator
  T* operator->()
  {
    return m_Object;
  }
};

class AirCraft
{
private:
  std::string m_Model;

public:
  AirCraft() :m_Model("Generic Model")
  {
    cout << "Generic model aircraft created" << endl;
  }

  AirCraft(const string& modelName) :m_Model(modelName)
  {
    cout << "Aircraft type" << m_Model << "is created!" << endl;
  }

  void SetAirCraftModel(const string& modelName)
  {
    cout << "Aircraft model changed from  " << m_Model << " to " << modelName << endl;
    m_Model = modelName;
  }

  ~AirCraft()
  {
    cout << "Destroying Aircraft of model:" << m_Model << "!" << endl;
  }
};

int main()
{
  // Create two aircraft objects. 
  smart_ptr<AirCraft> raptorPointer(new AirCraft("F-22 Raptor")); // Ref Count for raptorPointer = 1

  raptorPointer->SetAirCraftModel("B2 Bomber");   // rename the model using pointer access operator
  (*raptorPointer).SetAirCraftModel("B2 Spirit"); // rename the model using the pointer dereference operator

  smart_ptr<AirCraft> hornettPointer(new AirCraft("F-14 Hornett")); // Ref count for hornettPointer = 1

  raptorPointer = hornettPointer; // raptorPointer now points to "F14-Hornett".Ref count for hornett is 2. "F-22 Raptor" is destroyed. Ref count for hornett is 2

  return 0;
}