凌云的博客

行胜于言

漫谈 C++ 智能指针 09

分类:c++| 发布时间:2015-11-14 18:48:00


侵入式智能指针

我们之前介绍的 shared_ptr 是非侵入式智能指针。 非侵入式的意思是说使用 shared_ptr 时我们不用在我们自己的类中记录引用计数。 而侵入式智能指针通常要在我们自己的类中记录引用计数。 在 shared_ptr 中我们需要 new 一个 shared_count 来记录引用计数, 对于有较高性能要求的系统来说,这是一笔不必要的花销。 侵入式智能指针的提出就是为了解决这个问题,通过直接在客户类中记录引用计数, 避免额外的 shared_count 申请与释放。

实现侵入式智能指针

#include <cassert>
#include <atomic>

namespace MY_DEMO {

template<typename T>
class intrusive_ptr
{
public:
    intrusive_ptr(): px_(0) {
    }

    intrusive_ptr(T *p, bool add_ref = true): px_(p) {
        if (px_ && add_ref) T::intrusive_ptr_add_ref(px_);
    }

    intrusive_ptr(const intrusive_ptr &r): px_(r.px_) {
        if (px_) T::intrusive_ptr_add_ref(px_);
    }

    ~intrusive_ptr() {
        if (px_ != 0 ) T::intrusive_ptr_release(px_);
    }

    intrusive_ptr& operator=(const intrusive_ptr &r) {
        this_type(r).swap(*this);
        return *this;
    }

    intrusive_ptr& operator=(T *r) {
        this_type(r).swap(*this);
        return *this;
    }

    void reset(T *r = 0) {
        this_type(r).swap(*this);
    }

    T* get() const {
        return px_;
    }

    T* detach() {
        T *ret = px_;
        px_ = 0;
        return ret;
    }

    T& operator*() const {
        assert(px_ != 0);
        return *px_;
    }

    T* operator->() const {
        assert(px_ != 0);
        return px_;
    }

private:
    typedef intrusive_ptr this_type;

    void swap(intrusive_ptr &r) {
        T *tmp = px_;
        px_ = r.px_;
        r.px_ = tmp;
    }

private:
    T *px_;
};

template<typename T>
class intrusive_ref_counter
{
public:
    static void intrusive_ptr_add_ref(T *self) {
        if (self)
            ++self->ref_count_;
    }

    static void intrusive_ptr_release(T *self) {
        if (self && self->ref_count_ > 0 && !--self->ref_count_)
            delete self;
    }

protected:
    intrusive_ref_counter(): ref_count_(0) {
    }

    std::atomic_int ref_count_;
};

} // namespace MY_DEMO

在我们的实现中,我们规定所有使用 intrusive_ptr 的类需要实现 intrusive_ptr_add_ref 和 intrusive_ptr_release 两个静态成员函数。 当然你也可以直接继承 intrusive_ref_counter 。

使用侵入式智能指针

我们来写个简单的例子来测试下实现的侵入式智能指针。

#include <string>
#include <iostream>
#include <cassert>
#include <atomic>

// See intrusive_ptr above

using MY_DEMO::intrusive_ptr;
using MY_DEMO::intrusive_ref_counter;
using std::string;
using std::cout;
using std::endl;

class Person: public intrusive_ref_counter<Person>
{
public:
    Person(const string &name): name_(name) {
    }

    void dump() {
        cout << "name: " << name_ << endl
            << "ref_count_: " << ref_count_ << endl;
    }

private:
    string name_;
};

void test_intrusive_ptr()
{
    intrusive_ptr<Person> p(new Person("Jim"));
    p->dump();
    {
        intrusive_ptr<Person> p2(p);
        p->dump();
    }

    cout << "after p2 destruct" << endl;
    p->dump();

    {
        intrusive_ptr<Person> p3;
        p3 = p;
        p->dump();
    }

    cout << "after p3 destruct" << endl;
    p->dump();
}

输出为:

name: Jim
ref_count_: 1
name: Jim
ref_count_: 2
after p2 destruct
name: Jim
ref_count_: 1
name: Jim
ref_count_: 2
after p3 destruct
name: Jim
ref_count_: 1

可以看到可以正常工作。