【面试题】手撸shared_ptr的实现

本文介绍了如何实现一个简单的线程不安全的智能指针模板类Sptr,包括其默认构造、析构、拷贝构造、拷贝赋值、移动构造和移动赋值等操作。通过示例展示了Sptr类如何管理对象的生命周期,并通过refCnt()方法查看引用计数。此外,还给出了A类的构造和析构,以及在main函数中Sptr类的使用情况,如创建、拷贝、移动以及引用计数的变化等。
摘要由CSDN通过智能技术生成

简单实现了一个线程不安全的版本:

#include <iostream>

using namespace std;

int new_cnt = 0;
int del_cnt = 0;

template <class T>
class Sptr
{
public:
    // 默认构造和析构函数
    Sptr(T *ptr = nullptr) // 此时编译器不会生成默认的构造函数 无论有没有默认的实参
        : data_(ptr)
    {
        if (data_ != nullptr)
        {
            cout << "ref_cnt_ new cnt: " << ++new_cnt << endl;
            ref_cnt_ = new int(1);
        }
        cout << "in default Sptr()" << endl;
    }

    ~Sptr()
    {
        cout << "in ~Sptr()" << endl;
        decreRefCnt();
    }

    // 拷贝构造和拷贝赋值运算符
    Sptr(const Sptr &s)
    {
        data_ = s.data_;
        ref_cnt_ = s.ref_cnt_;
        increRefCnt();
        cout << "in copy Sptr()" << endl;
    }

    Sptr &operator=(const Sptr &s) // 双目运算的重载,入参
    {
        cout << "in copy = Sptr()" << endl;
        if (&s == this)
        {
            // 自拷贝 直接返回
            return *this;
        }

        decreRefCnt(); // 自身原来指向的内存引用要减1
        data_ = s.data_;
        ref_cnt_ = s.ref_cnt_;
        increRefCnt();
        return *this;
    }

    // 移动构造和移动赋值运算符
    Sptr(Sptr &&s)
    {
        cout << "in move Sptr()" << endl;
        if (&s == this)
        {
            return;
        }

        data_ = s.data_;
        ref_cnt_ = s.ref_cnt_;
        s.data_ = nullptr;
        s.ref_cnt_ = nullptr;
    }

    Sptr &operator=(Sptr &&s)
    {
        cout << "in move = Sptr()" << endl;
        if (&s == this)
        {
            return *this;
        }

        decreRefCnt(); // 自身原来指向的内存引用要减1
        data_ = s.data_;
        ref_cnt_ = s.ref_cnt_;
        s.data_ = nullptr;
        s.ref_cnt_ = nullptr;
        return *this;
    }

    int refCnt() const 
    {
        if (ref_cnt_ == nullptr)
        {
            return -1;
        }
        cout << "ref_cnt:" << *ref_cnt_ << endl;
        return (*ref_cnt_);
    }

    T &operator*() const // 单目运算 不带入参
    {
        return *data_;
    }

    T *operator->() const // 单目运算 不带入参
    {
        return data_;
    }

    T *get() const
    {
        return data_;
    }

private:
    void increRefCnt()
    {
        if (ref_cnt_ == nullptr)
        {
            return;
        }   
        (*ref_cnt_)++;
    }

    void decreRefCnt()
    {
        if (ref_cnt_ == nullptr)
        {
            return;
        }

        (*ref_cnt_)--;
        if (*ref_cnt_ == 0)
        {
            cout << "ref_cnt_ del cnt: " << ++del_cnt << endl;
            delete data_;
            delete ref_cnt_;
        }
        else if (*ref_cnt_ < 0)
        {
            cout << "ref_cnt_ del cnt: " << ++del_cnt << endl;
            delete ref_cnt_;
        }
    }

    T *data_ = nullptr;
    int *ref_cnt_ = nullptr;
};

class A
{
public:
    A();
    A(int a) { num = a; }
    ~A();

    int num = 10;
};

A::A()
{
    cout << "in A()" << endl;
}

A::~A()
{
    cout << "in ~A()" << endl;
}

int main()
{
    Sptr<A> ptr = new A; // 默认构造
    ptr.refCnt();
    cout << "num is " << ptr->num++ << endl;
    cout << "num is " << (*ptr).num++ << endl;
    cout << "num is " << ptr.get()->num << endl;
    Sptr<A> ptr1(ptr); // 拷贝构造
    ptr1.refCnt();
    ptr.refCnt();
    Sptr<A> ptr2;
    ptr2.refCnt();
    ptr2 = ptr1; // 拷贝赋值
    ptr2.refCnt();
    ptr1.refCnt();
    ptr.refCnt();
    {
        Sptr<A> tmp;
        tmp.refCnt();
    }

    {
        Sptr<A> ptr3 = std::move(ptr2); // 移动构造
        ptr3.refCnt();
        ptr1.refCnt();
        ptr.refCnt();

        Sptr<A> ptr4;
        ptr4 = std::move(ptr3); // 移动赋值
        ptr4.refCnt();
        ptr1.refCnt();
        ptr.refCnt();

        cout << "ptr3.refCnt: " << ptr3.refCnt() << endl;
    }

    {
        Sptr<A> a1;
        auto a2 = a1;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值