Skip to content

shared_ptr简易实现版 #33

Description

@bingtaoli

在C语言中,我们设计接口往往会为对象设计两个接口:

  • addref(void *)
  • delref(void *)

使用场景比如:

obj *p = create_obj();  //引用计数为1
addref(p);                //引用计数2
loop_queue(p);  //放到队列中稍后处理。那么 需要先addref保证到时候使用到p的时候p没有被销毁。
p->xxx = yyy;
delref(p);  //引用计数1

在cpp中,智能指针就起到类似作用。它帮助程序员更好地管理内存,不再malloc后忘记了free。
上面的例子就变成了:

MySharedPtr<obj> p(create_obj());
loop_queue(p);   // 传参数会拷贝p生成一个临时变量,原始资源的引用计数会自动+1.
p->xxx = yyy;

智能指针协助你,没有了自己管理计数的麻烦。

关键几点:

  • 默认构造函数
  • 参数为指针的构造函数
  • 拷贝构造函数
  • 移动拷贝构造函数
  • 析构函数
  • get()
  • use_count()
  • 重载->
  • 重载*
  • swap
#include <iostream>
#include <stdio.h>
#include <assert.h>
using namespace std;

#define EXPECT_TRUE(exp) if (!(exp)) assert(0) 
#define EXPECT_EQ(a, b) if ((a) != (b)) { \
    cout << a << " != " << b << endl; \
    assert(0); \
} else {\
    printf("pass\n");\
}

template <typename T>
class MySharedPtr
{
public:
    MySharedPtr() {
        ref = NULL;
        ptr = NULL;
    }

    // 析构
    ~MySharedPtr() {
        if (!ref) {
            return;
        }
        (*ref)--;
        if (*ref == 0) {
            delete ptr;
            delete ref;
        }
    }

    // 裸指针构造
    MySharedPtr(T *raw) {
        if (raw) {
            ref = new int(1);
            ptr = raw; 
        }
    }    

    // 拷贝构造,共享资源,引用+1
    MySharedPtr(const MySharedPtr &p) {
        cout << "copy construct" << endl;
        if (p.ptr) {
            ptr = p.ptr;
            ref = p.ref;
            (*ref)++;
        }
    }

    /**
    * 移动构造,把p管理的资源偷到自己这里
    * @param p 右值引用
    */ 
    MySharedPtr(MySharedPtr &&p) {
        cout << "move construct" << endl;
        ref = NULL;
        ptr = NULL;
        this->swap(p);
    }

    // 操作符重载
    void operator =(const MySharedPtr &p) {
        // 交出自己的管理权
        MySharedPtr<T> tmp;
        this->swap(tmp);
        ptr = p.ptr;
        ref = p.ref;
        (*ref)++;
    }

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

    T& operator *() {
        return *ptr;
    }

    int use_count() {
        if (ref) {
            return *ref;
        }
        return 0;
    }

    T *get() {
        return ptr;
    }

    // 交换管理权
    void swap(MySharedPtr &p) {
        std::swap(this->ref, p.ref);
        std::swap(this->ptr, p.ptr);
    }

    void reset() {
        // 交出自己的管理权
        MySharedPtr<T> tmp;
        this->swap(tmp);
    }

private:
    int *ref;
    T *ptr;
};

class Test
{
public:
    Test() : n1(0), n2(0) {
        cout << "Test created" << endl;
    }

    ~Test() {
        cout << "Test deleted" << endl;
    }

    Test(int arg) : n1(0), n2(0) {
        cout << "Test created with arg:" << arg << endl;
        n1 = arg; 
    }

    int get_n1() {
        return n1;
    }

private:
    int n1;
    int n2;
};

void swap_test()
{
    printf("------------------------%s--------------------------\n", __FUNCTION__);
    MySharedPtr<Test> a(new Test(1024));
    EXPECT_EQ(a.use_count(), 1);
    MySharedPtr<Test> b;
    b.swap(a);
    EXPECT_EQ(a.use_count(), 0);
    EXPECT_EQ(b.use_count(), 1);
}

void construct_test()
{
    printf("------------------------%s--------------------------\n", __FUNCTION__);
    MySharedPtr<Test> a(new Test(1024));
    Test *p;
    p = a.get();
    EXPECT_EQ(p->get_n1(), 1024);
    // 重载=
    MySharedPtr<Test> b = a;
    EXPECT_EQ(a.use_count(), 2);
    // 拷贝构造
    MySharedPtr<Test> c(b);
    EXPECT_EQ(a.use_count(), 3);
    // 重新赋值
    MySharedPtr<Test> d(new Test);
    c = d;
    EXPECT_EQ(a.use_count(), 2);
}

void move_test()
{
    printf("------------------------%s--------------------------\n", __FUNCTION__);
    // 移动拷贝
    MySharedPtr<Test> a(new Test(1024));
    EXPECT_EQ(a.use_count(), 1);
    MySharedPtr<Test> b(std::move(a));
    EXPECT_EQ(a.use_count(), 0);
    EXPECT_EQ(b.use_count(), 1);
    EXPECT_EQ(b->get_n1(), 1024);
}

void reset_test()
{
    // reset测试
    printf("------------------------%s--------------------------\n", __FUNCTION__);
    MySharedPtr<Test> a(new Test());
    EXPECT_EQ(a.use_count(), 1);
    a.reset();
    EXPECT_EQ(a.use_count(), 0);
}

int main() 
{
    swap_test();
    construct_test();
    move_test();
    reset_test();
    return 0;    
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions