面试手撕-shared_ptr

面试手撕-shared_ptr

shared_ptr基本概念

std::shared_ptr 是C++标准库中的一个智能指针类型,它提供了自动的内存管理功能,通过引用计数机制来决定所管理的对象何时应该被删除。当最后一个指向对象的 shared_ptr 离开作用域或者被重置时,它所指向的对象会被自动删除,从而防止了内存泄漏。

实现一个shared_ptr

使用基础语法和标准库来实现一个shared_ptr所需要实现的成员变量和成员函数:

成员变量/属性

  • 原始指针 (T* ptr): 用于存储实际的原始指针,指向动态分配的对象
  • 引用计数 (std::size_t* ref_count): 用于跟踪有多少个 shared_ptr 实例共享同一个对象。通常是一个动态分配的整型指针,因为每个 shared_ptr 实例都需要能够修改这个计数。

成员函数

  1. 构造函数 (shared_ptr(T* ptr = nullptr)): 初始化 shared_ptr,如果给定指针,则分配新的引用计数并指向该对象。
  2. 拷贝构造函数 (shared_ptr(const shared_ptr& other)): 复制另一个 shared_ptr,增加引用计数。
  3. 移动构造函数 (shared_ptr(shared_ptr&& other)): 移动另一个 shared_ptr,不增加引用计数,而是将源 shared_ptr 设置为 nullptr。
  4. 析构函数 (~shared_ptr()): 释放资源,如果引用计数减至0,则删除原始指针指向的对象及引用计数本身。
  5. 重载赋值运算符 (copy assignment 和 move assignment): 类似于拷贝构造函数和移动构造函数,也需要更新引用计数。
  6. 解引用运算符 (T& operator*(), T* operator->()): 允许像普通指针一样访问对象。
  7. 获取原始指针 (T* get()): 返回原始指针。
  8. 重置 (void reset(T* ptr = nullptr)): 释放当前管理的对象(如果引用计数允许),并可选地开始管理一个新的对象。
  9. 获取引用计数 (可选,非标准功能)(std::size_t use_count()): 返回当前的引用计数。

最少实现的部分

2个成员变量是一定要设置的,对于成员函数:
构造函数、拷贝构造函数、析构函数、赋值运算符、*运算符、->运算符

代码实现

精简版实现
template<typename T>
class share_ptr{
public:
   //默认构造函数
   explicit shared_ptr(T* ptr = nullptr):m_ptr(ptr), m_refCount(new size_t(1)){}
   //拷贝构造函数
   shared_ptr(const shared_ptr<T>& sp):m_ptr(sp.m_ptr), m_refCount(sp.m_refCount){
       (*m_refCount)++;
   }
   //析构函数
   ~shared_ptr(){
       decreaseRefCountAndDeleteIfNecessary();
   }
   //运算符重载
   //赋值运算符重载
   shared_ptr<T> operator=(const shared_ptr<T>& sp){
       if(this!=sp){
           decreaseRefCountAndDeleteIfNecessary();
           m_ptr = sp.m_ptr;
           m_refCount = sp.m_refCount;
           (*m_refCount)++;
       }
       return this;
   }
   //解引用运算符重载
   T& operator*() const{
       return *m_ptr;
   }
   //箭头运算符重载
   T* operator->() {
       return m_ptr;
   }

private:
   T* m_ptr;
   std::size_t* m_refCount;
   void decreaseRefCountAndDeleteIfNecessary(){  //当实例对象的shared_ptr出作用域的时候进行检查是否需要释放资源
       if(--(*m_refCount) == 0){
           delete m_ptr;
           delete m_refCount;
       }
   }
};

完整版本

template <typename T>
class shared_ptr {
private:
    T* m_ptr{nullptr};
    std::size_t* m_refCount{nullptr};
public:
    // 构造函数
    explicit shared_ptr(T* ptr = nullptr) : m_ptr(ptr), m_refCount(new std::size_t(1)) {}

    // 拷贝构造函数
    shared_ptr(const shared_ptr& other) : m_ptr(other.m_ptr), m_refCount(other.m_refCount) {
        ++(*m_refCount);
    }

    // 赋值运算符(拷贝赋值)
    shared_ptr& operator=(const shared_ptr& other) {
        if (this != &other) {
            if (--(*m_refCount) == 0) {
                delete m_ptr;
                delete m_refCount;
            }
            m_ptr = other.m_ptr;
            m_refCount = other.m_refCount;
            ++(*m_refCount);
        }
        return *this;
    }

    // 解引用运算符
    T& operator*() const {
        return *m_ptr;
    }

    // 箭头操作符
    T* operator->() const {
        return m_ptr;
    }

    // 获取原始指针
    T* get() const {
        return m_ptr;
    }

    // 重置
    void reset(T* ptr = nullptr) {
        if (--(*m_refCount) == 0) {
            delete m_ptr;
            delete m_refCount;
        }
        m_ptr = ptr;
        m_refCount = new std::size_t(1);
    }

    // 获取引用计数
    std::size_t use_count() const {
        return m_refCount ? *m_refCount : 0;
    }

    // 析构函数
    ~shared_ptr() {
        if (--(*m_refCount) == 0) {
            delete m_ptr;
            delete m_refCount;
        }
    }
};
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
shared_ptrC++11 中引入的智能指针类型,可用于管理动态分配的对象。它是通过引用计数的方式来跟踪对象的使用情况,并在不再需要时自动释放相关的内存。 shared_ptr 的过程大致如下: 1. 定义 shared_ptr 类:首先,你需要定义一个类模板 shared_ptr,它包含两个主要成员:指向动态分配内存的原始指针和一个指向引用计数的指针。此外,你还需要实现构造函数、析构函数、拷贝构造函数和赋值运算符等成员函数。 2. 初始化:在 shared_ptr 的构造函数中,你需要将原始指针和引用计数初始化为空,并将引用计数置为 1。 3. 拷贝构造函数和赋值运算符:在拷贝构造函数和赋值运算符中,你需要更新原始指针和引用计数。当一个 shared_ptr 被拷贝时,引用计数应该递增;当一个 shared_ptr 被赋值给另一个 shared_ptr 时,应该先递减左操作数的引用计数,然后再递增右操作数的引用计数。 4. 引用计数管理:你需要实现对引用计数的正确管理。当引用计数变为零时,表示没有任何 shared_ptr 指向该对象,此时应该释放相关的内存。 5. 解引用操作符和箭头操作符重载:为了使 shared_ptr 使用起来像原始指针一样,你需要重载解引用操作符和箭头操作符,以便可以直接访问对象或对象的成员。 6. 其他辅助函数:你可以实现其他辅助函数,如 get() 函数用于获取原始指针,reset() 函数用于重置 shared_ptr,以及 operator bool() 函数用于检查 shared_ptr 是否为空等。 需要注意的是,动实现 shared_ptr 需要处理好线程安全性和异常安全性等问题,这需要一定的经验和技巧。因此,在实际项目中,建议使用标准库提供的 shared_ptr 类型,以便确保代码的可靠性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值