C++基于模板实现智能指针

某厂面试,当时反正是没写出来,估计是寄了,事后做个记录。

#include <iostream>
#include <mutex>
using namespace std;

class ObjectElement {
private:
    char *addr;
    int size;
    void release() {
        addr = nullptr;
        size = 0;
    }

public:
    ObjectElement(int size) {
        cout<< "construct: "<<this<<endl;
        this->size = size;
        addr = new char[size];
    }

    ~ObjectElement() {
        cout<< "release: "<<this<<endl;
        delete []addr;
        release();
    }

    void PrintTest() {
        cout<<"ObjectElement"<<endl;
    }

};


// 注意不是线程安全的,需要加锁

template <typename T>
class SharedPtr {
private:
    // 可以用一个额外的ControlBlock 结构存储以下两个私有变量,此处只需要一个指针,做不做两可
    T *ptr;
    int *ref_count; // 核心,如果直接用int:每个shared_ptr 就会有自己的引用计数器,它们不会同步更新

    void release() { // private
        if(ref_count != nullptr && --(*ref_count) == 0) {
            delete ptr;
            delete ref_count;
        }
    }

public:

    SharedPtr() : ptr(nullptr), ref_count(nullptr) {}

    explicit SharedPtr(T *p) {
        ptr = p;
        ref_count = new int(1);
    }

    // 注意只有在拷贝或者赋值的时候才会有引用计数的增加

    // 拷贝构造,增加引用计数
    SharedPtr(const SharedPtr &s) noexcept {
        ptr = s.ptr;
        ref_count = s.ref_count;
        if(ref_count != nullptr) {
            (*ref_count)++;
        }
    }

    // 移动构造,没有增加引用计数
    SharedPtr(SharedPtr &&s) noexcept {
        ptr = s.ptr;
        ref_count = s.ref_count;
        s.ptr = nullptr;
        s.ref_count = nullptr;
    }

    // 拷贝赋值运算符,与拷贝构造类似,但是需要先判断是否是自己,注意返回自身引用
    SharedPtr& operator=(const SharedPtr &s) noexcept{
        if(this == &s) {
            release(); // 重要!删除原有的

            ptr = s.ptr;
            ref_count = s.ref_count;
            if(ref_count != nullptr) {
                (*ref_count)++;
            }
        }
        return *this;
    }

    // 移动赋值运算符,同理
    SharedPtr& operator=(SharedPtr &&s) noexcept{
        if(this == &s) {
            release(); // 重要!删除原有的
            
            ptr = s.ptr;
            ref_count = s.ref_count;
            s.ptr = nullptr;
            s.ref_count = nullptr;
        }
        return *this;
    }

    // 解引用,重载*,返回T对象
    T& operator*() const {
        return *ptr;
    }

    // 重载指针操作符,使得可以类似->调用
    T* operator->() const{
        return ptr;
    }

    // 获取裸指针,同上
    T* get() const{
        return ptr;
    }

    int use_count() const {
        return (ref_count!=nullptr?(*ref_count):0);
    }

    void reset(T* p = nullptr) {
        release();

        ptr = p;
        if(p == nullptr) {
            ref_count = nullptr;
        }
        else {
            ref_count = new int(1);
        }
    }

    ~SharedPtr() {
        release();
    }


};





int main() {

    ObjectElement *obj = new ObjectElement(100);

    SharedPtr<ObjectElement> sptr1(obj);
    SharedPtr<ObjectElement> sptr2 = sptr1;

    cout<<sptr1.use_count()<<endl;
    cout<<sptr2.use_count()<<endl;

    (*sptr1).PrintTest();
    sptr1->PrintTest();
    sptr1.get()->PrintTest();


    sptr1.reset();

    cout<<sptr1.use_count()<<endl;
    cout<<sptr2.use_count()<<endl;


    return 0;
}

预期输出为:

posted @ 2024-08-30 05:55  真昼小天使daisuki  阅读(23)  评论(0编辑  收藏  举报