IUnknown
   COM
  is Microsoft's component framework. It was created in the 90's but still used for native development and UWP. All components in this framework must support the IUnknown interface:
interface IUnknown
{
   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) = 0;
   virtual ULONG   STDMETHODCALLTYPE AddRef() = 0;
   virtual ULONG   STDMETHODCALLTYPE Release() = 0;
};
This interface has three functions:
  - 
    
QueryInterface to query and access the components supported
    interfaces
   
  AddRef to increment the reference count 
  - 
    
Release to decrement the reference count. When the reference
    count goes to zero the component is destroyed.
   
   Client code must adhere to the protocol of incrementing the interface
  when using it and releasing the interface when done. Mostly components returned 
  from functions are already incremented so that client code only need to
  decrement the reference count.
 Example
    For the example here the function to create error info is used. The
  address of a pointer must supplied and when successful the interface must be
  released:
ICreateErrorInfo* pErrorInfo = nullptr;
HRESULT hr = ::CreateErrorInfo(&pErrorInfo);
if (pErrorInfo)
{
   pErrorInfo->Release();
}
   One of the major error causes when using COM is that reference counts
  are not administered correctly:
  - 
    when reference counts are more released than incremented by client code it
    causes cashes and access violations. This may happen beyond the fault
    location (in time and space).
  
 
  - 
    when too few reference counts are released it may cause resource
    leaks. For example on my work in the past a colleague released one
    VMR9
    interface too little. This resulted in a  full thread leak since the VMR9 is a fat object.
   
 Smart pointer
   Luckily Microsoft has acknowledged this problem and created smart
  pointer classes for COM interfaces. There are two flavor's. One comes from the compiler support classes '_com_ptr_t'. The other one is CComPtr and comes from the 
  ATL library. The CComPtr is desmontrated in the followign examples.
  Code in above example becomes easier especially when there would be multiple return
  paths:
CComPtr<ICreateErrorInfo> ptrErrorInfo;
HRESULT hr = ::CreateErrorInfo(&ptrErrorInfo);
if (ptrErrorInfo)
{
   //no release necessary
}
   As usual with smart pointers they work transparent. One can assign them
  to other smart pointers or even return from functions: 
CComPtr<ICreateErrorInfo> CreateErrorInfoPtr()
{
  CComPtr<ICreateErrorInfo> ptrErrorInfo;
  HRESULT hr = ::CreateErrorInfo(&ptrErrorInfo);
  return ptrErrorInfo;
}
const CComPtr<ICreateErrorInfo> ptr = CreateMyErrorInfoPtr();
   With returning raw pointers a leak is easily created when the client
  code ignores the created interface return value. In above case with smart
  pointers it is suboptimal but it wouldn't hurt when client code ignores the return value since
  the returned temporary object goes out of scope and releasing thereby the
  created interface.
 Implementation
    A possible implementation could be as follow (borrowed and modified from the original source):
template <class T>
class CComPtr
{
public:
   CComPtr()
      : m_p(nullptr)
   {
   }
   CComPtr(T* p)
      : m_p(p)
   {
      if (m_p != nullptr)
         m_p->AddRef();
   }
   CComPtr(const CComPtr& rptr)
      : CComPtr(rptr.m_p)
   {
   }
   ~CComPtr()
   {
      if (m_p)
         m_p->Release();
   }
   CComPtr& operator=(const CComPtr& rptr)
   {
      if (m_p != rptr.m_p)
      { 
         if (m_p) 
            m_p->Release();
         
         m_p = rptr.m_p;
         m_p->AddRef();
      }
      return *this;
   }
private:
   T*    m_p;
};
Conclusion
    CComPtr is one the best addition to COM programming. It greatly
  simplifies COM client implementaitons and solves almost completely all
  reference counting and tracking issues. It's actually hard to do wrong with
  CComPtr since it also asserts when a contained interface is overwritten
  accidently.
   'Effective COM' mentions in item 22 that 'smart interface pointers add
  at least as much complexity as they remove'. I strongly disagree as can be
  read from this article. The book mentions a small problem with old CComPtr
  which is also solved in the latest release of ATL.