【网易面试题】如何实现一个线程安全的shared_ptr智能指针

题目描述

网易一面遇到过这么一个题目,面试官要求自己实现一个线程安全的shared_ptr智能指针。

题目分析

可能很多人只知道shared_ptr是C++11模块库的头文件定义的一个智能指针,即shared_ptr模版。只要将new运算符返回的指针交给shared_ptr这个“管家”,就不必担心在哪里没有delete p了。shared_ptr在被删除的时候会自动执行delete p。通过 shared_ptr 的构造函数,可以让 shared_ptr 对象托管一个 new 运算符返回的指针,写法如下:

        shared_ptr<T> ptr(new T)

此后ptr就像T指针那样用,即ptr就是new动态分配的对象。多个shared_ptr可以共同托管一个指针p,当所有曾经托管p的shared_ptr都解除了对p的托管就会执行delete p。
这个题目拿到手后得搞清楚shared_ptr的原理
1.在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
2.在对象被销毁时,就说明自己不使用该资源了,对象的引用计数减一。
3.如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
4.如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。

而且题目既然要求线程安全,就得考虑下面两个问题:
1.智能指针对象中的引用技术是多个对象所共享的,两个线程同时对智能指针进行++或–运算,这个计数原来是1,++了两次可能还是2,这样引用技术就错乱了。会导致资源未释放或者程序崩溃的问题。所以只能指针中引用计数++、–是需要加锁的,也就是说引用计数的操作是线程安全的。
2.智能指针的对象存放在堆上,可能会导致线程安全问题。

线程安全的智能指针代码如下:

#include <utility>
#include <string>
#include <mutex>

using namespace std;

class Counter
{
public:
   Counter() :
     m_Counter(0)
   {}       

   Counter(const Counter&) = delete;
   Counter& operator=(const Counter&) = delete; 
   ~Counter() {}
   void reset() {
       m_Counter = 0;
   }
   unsigned int get() const
   {
       return m_Counter;
   }
   void operator++()
   {
       m_Counter++;
   }
    
   void operator++(int)
   {
       m_Counter++;
   }

    void operator--()
   {
       m_Counter--;
   }
    
   void operator--(int)
   {
       m_Counter--;
   }
 
   friend ostream& operator<<(ostream& os, const Counter& c)
   {
       os << "Counter value: " << c.m_Counter << endl;
       return os;
   }
  
private:
   unsigned int m_Counter{};      
};

template<typename T>
class Shared_ptr
{
public:
 explicit Shared_ptr(T *ptr=nullptr):
      m_ptr(ptr),
      m_pCounter(new Counter()),
       m_pMutex(new std::mutex)
   {
       if(ptr)
       {
           AddRefCount();
       }
   }
   
   Shared_ptr(Shared_ptr<T>&  sp)
   {
       m_ptr = sp.m_ptr;
       m_pCounter = sp.m_pCounter;
       AddRefCount();
   }

   Shared_ptr<T>& operator=(const Shared_ptr<T>& sp)
   {
       if(m_ptr != sp.m_ptr)
       {
           Realse();
           m_ptr = sp.m_ptr;
           m_pCounter = sp.m_pCounter;
           m_pMutex = sp.m_pMutex;
           AddRefCount();
       }
   }

    T *operator->()
    {
        return m_ptr;
    }

    T& operator*()
    {
        return *m_ptr;
    }  
    
    T *get()
    {
        return m_ptr;
    }
        
    unsigned int UseCount()
    {
        return m_pCounter->get();
    }
    
    ~Shared_ptr()
    {
       Realse();    
    }

private:
  void AddRefCount()
  {
      m_pMutex->lock();
      ++(*m_pCounter);
      m_pMutex->unlock();
  }


 void Realse()
 {
    bool deleteflag = false;
    m_pMutex->lock();
    --(*m_pCounter);
    if(m_pCounter->get() == 0)
    {
        delete m_pCounter;
        delete m_ptr;
        deleteflag = true;
    }
    m_pMutex->unlock();
    if(deleteflag == true)
      delete m_pMutex;
 }    

private:
 T *m_ptr;
 std::mutex *m_pMutex;
 Counter *m_pCounter; 
};
上一篇:OpenCV学习笔记16_常用边缘检测算法


下一篇:C++智能指针(2)—— unique_ptr