【C++基础】手撕shared_ptr

总体思路

  1. 使用类模板来实现多类型支持

  2. 构造函数(动态创建)、析构函数(销毁对象)

  3. 拷贝构造函数

  4. 拷贝运算符(->、*)

  5. 实现移动构造和移动运算符

  6. 对于引用计数的操作服从智能指针的设计规则

整体框架

tmplate
class new_shared_ptr {
pubilc:
    new_shared_ptr();
 
    new_shared_ptr(const new_shared_ptr& p);                 //构造
 
    ~new_shared_ptr();                                       //析构
 
    new_shared_ptr& operator=(const new_shared_ptr& obj);  //拷贝运算符

    new_shared_ptr(new_shared_ptr&& dying_obj);             // 移动构造

    new_shared_ptr& operator=(new_shared_ptr&& dying_obj);  //移动赋值运算符
    
    int operator->();        //->运算符
    
    int operator*();         //* 运算符
 
private:
    T* ptr;
    int* ref_count;
    mutex *m_pMutex;
}

构造函数

new_shared_ptr(): ptr(new T), ref_count(new int(1)), mutex(new mutex) {}

拷贝构造函数

new_shared_ptr(const new_shared_ptr& p) {
    //先对当前对象进行初始化
    ptr = p.ptr;
    ref_count = p.ref_count;
    mutex = p.mutex;
    //判断拷贝进来的指针是否指向空,不指向空表明当前地址多了一个指向,引用计数加一
    if (p != nullptr) {
        m_pMutex->lock();
        (*ref_count)++;
        m_pMutex->unlock();
    }
}

 重载=、->、* 运算符

new_shared_ptr& operator=(const new_shared_ptr& obj) {
    //检查自赋值
    if (obj.ptr == ptr) return *this;
    //防止空指针指向别处
    if (ptr) {
        //自身指向即将改变,判断原先指向的地址是否销毁
        m_pMutex->lock();
        (*ref_count)--;
        m_pMutex->unlock();
        if (ref_count == 0) {
            delete ptr;
            delete ref_count;
            delete m_pMutex;
        }
        ptr = obj.ptr;
        ref_count = obj.ref_count;
        m_pMutex = obj.m_pMutex;
        m_pMutex->lock();
        (*ref_count)++;
        m_pMutex->unlock();
    }
    return *this;
}
 
T* operator->() return ptr;
T& operator*() return *ptr;

移动构造

当使用移动构造函数创建一个新的智能指针并将另一个智能指针的资源所有权转移给它时,移动构造不会影响引用计数。引用计数会在资源所有权转移后保持不变,原来的智能指针会被置为  nullptr ,不再指向资源。这确保资源的唯一所有权。

new_shared_ptr(new_shared_ptr&& dying_obj)
      : ptr(nullptr), ref_count(nullptr) {
  // 初始化后,调用swap,交换指针和引用计数,相当于清除了原有的shared_ptr,把它们都置为nullptr了
    dying_obj.swap(*this);
  }

  void swap(new_shared_ptr& other) {
    std::swap(ptr, other.ptr);
    std::swap(ref_count, other.ref_count);
  }

移动赋值

当使用移动赋值运算符将一个智能指针的资源所有权转移给另一个智能指针时,移动赋值不会影响引用计数。与移动构造类似,资源的所有权转移后,原来的智能指针会被置为 nullptr ,引用计数保持不变。

new_shared_ptr& operator=(new_shared_ptr&& dying_obj) {
    /* 创建一个临时变量,将待移动的智能指针转移到临时变量 */
    new_shared_ptr(std::move(dying_obj)).swap(*this);
    return *this;
  }

析构函数

~new_shared_ptr() {
    if (!ptr || (*ref_count == 1)) {
        delete ptr;
        delete m_pMutex;
        delete ref_count;
    } else {
        m_pMutex->lock();
        (*ref_count)--;
        m_pMutex->unlock();
    }
}

你可能感兴趣的:(C++基础,c++,开发语言)