C++笔记 - 实现引用计数指针

281

引用计数指针是通过计数器记录资源的占用情况,能减少资源重复创建,达到资源高效复用的效果。当计数器到达0时,表明资源没有被引用,可以被释放。实现引用计数指针的关键在于:

  • 实现计数器
  • 实现构造函数和赋值函数
  • 实现析构函数

下面是实现计数器的代码:

#include <cassert>
#include <iostream>

class counter {
  public:
    counter() : m_count(1) {}
    void add() { ++m_count; }
    size_t sub() { return --m_count; }
    size_t get() const { return m_count; }

  private:
    size_t m_count;
};

代码简单,仅是实现计数器的增、减和获取功能。


下面是实现构造函数、析构函数和帮助函数:

template <typename T> class shared_pointer {
  public:
      // 默认构造函数
    explicit shared_pointer(T *ptr = nullptr) noexcept : m_ptr(ptr) {
        m_counter = new counter();
    }

    // 拷贝构造函数
    shared_pointer(shared_pointer &other) noexcept {
        other.m_counter->add();
        m_ptr = other.m_ptr;
        m_counter = other.m_counter;
    }

    // 移动构造函数,移动资源
    shared_pointer(shared_pointer &&other) noexcept {
        m_ptr = other.m_ptr;
        m_counter = other.m_counter;
        other.m_ptr = nullptr;
        other.m_counter = nullptr;
    }

    // 赋值,仅仅是交换资源
    shared_pointer &operator=(shared_pointer &rhs) noexcept {
        rhs.swap(*this);
        return *this;
    }

    // 移动赋值,仅仅是交换资源
    shared_pointer &operator=(shared_pointer &&rhs) noexcept {
        rhs.swap(*this);
        return *this;
    }

    ~shared_pointer() noexcept {
        if (m_counter && !m_counter->sub()) {
            delete m_counter;
            if (m_ptr) {
                delete m_ptr;
            }
        }
    }

    size_t count() const noexcept {
        if (!m_counter) return 0;
        return m_counter->get();
    }

    void swap(shared_pointer &rhs) noexcept {
        std::swap(m_ptr, rhs.m_ptr);
        std::swap(m_counter, rhs.m_counter);
    }

  private:
    T *m_ptr;
    counter *m_counter;
};

template <typename T>
void swap(shared_pointer<T> &lhs, shared_pointer<T> &rhs) noexcept {
    lhs.swap(rhs);
}

上面实现相关函数的功能:

  • 默认构造函数:创建资源

  • 拷贝构造函数:共享资源

  • 移动构造函数:移动资源

  • 赋值、移动赋值函数和 swap 函数: 交换资源

  • 析构函数:释放资源


下面是测试代码:

int main(void) {
    /* std::string *str = nullptr; */
    std::string *str = new std::string{"hello world"};

    // 创建资源
    shared_pointer<std::string> sp_1{str};
    assert(sp_1.count() == 1);

    // 共享资源
    shared_pointer<std::string> sp_2{sp_1};
    assert(sp_1.count() == 2);
    assert(sp_2.count() == 2);

    // 交换资源
    shared_pointer<std::string> sp_3;
    sp_3 = sp_2;
    assert(sp_1.count() == 2);
    assert(sp_2.count() == 1);
    assert(sp_3.count() == 2);

    // 移动资源
    shared_pointer<std::string> sp_4{std::move(sp_1)};
    assert(sp_1.count() == 0);
    assert(sp_2.count() == 1);
    assert(sp_3.count() == 2);
    assert(sp_4.count() == 2);

    // 交换资源
    shared_pointer<std::string> sp_5;
    sp_5 = std::move(sp_4);
    assert(sp_1.count() == 0);
    assert(sp_2.count() == 1);
    assert(sp_3.count() == 2);
    assert(sp_4.count() == 1);
    assert(sp_5.count() == 2);

    return 0;
}

上面是引用计数指针的简单实现,功能还是非常有限的,但作为学习智能指针还是有不错的。