凌云的博客

成功=工作+游戏+少说空话

漫谈 C++ 智能指针 06

分类:c++| 发布时间:2015-11-01 21:28:00


改进 shared_ptr

在上一篇文章中,我们实现了带引用计数的智能指针 shared_ptr 。 现在我们来改进一下实现,使得代码更清晰,并且使其可以支持 weak_ptr (下一篇讲 weak_ptr 的应用场景以及实现)。

#include <algorithm>

namespace MY_DEMO {

template<typename T>
class sp_count
{
public:
    sp_count(T *p): p_(p), use_count_(0) {
    }

    void add_ref_copy() {
        ++use_count_;
    }

    void dispose() {
        delete p_;
    }
    void release() {
        if (--use_count_ == 0) {
            dispose();
            delete this;
        }
    }

private:
    int use_count_;
    T *p_;
};

template<typename T>
class shared_count
{
public:
    explicit shared_count(T *p = 0): pi_(new sp_count<T>(p)) {
    }

    ~shared_count() {
        if (pi_ != 0) pi_->release();
    }

    shared_count(const shared_count &r): pi_(r.pi_) {
        if (pi_ != 0) {
            pi_->add_ref_copy();
        }
    }

    shared_count& operator=(const shared_count &r) {
        sp_count<T> *tmp = r.pi_;

        if (pi_ != tmp) {
            if (tmp != 0) tmp->add_ref_copy();
            if (pi_ != 0) pi_->release();
            pi_ = tmp;
        }

        return *this;
    }

    void swap(shared_count &r) {
        sp_count<T> *tmp = r.pi_;
        r.pi_ = pi_;
        pi_ = tmp;
    }

private:
    sp_count<T> *pi_;
};

template<typename T>
class shared_ptr
{
public:
    typedef shared_ptr<T> this_type;

    explicit shared_ptr(T *p = 0): px_(p), pn_(p) {
    }

    shared_ptr(const shared_ptr &r): px_(r.px_), pn_(r.pn_) {
    }

    ~shared_ptr() {
    }

    void reset(T *p) {
        if (p == px_)
            return;

        this_type(p).swap(*this);
    }

    T* get() {
        return px_;
    }

    void swap(shared_ptr &r) {
        std::swap(px_, r.px_);
        pn_.swap(r.pn_);
    }

    shared_ptr& operator= (const shared_ptr<T> &r) {
        px_ = r.px_;
        pn_ = r.pn_;
        return *this;
    }

    bool operator! () const {
        return !px_;
    }

    T& operator* () const {
        return *px_;
    }

    T* operator-> () const {
        return px_;
    }

private:
    T *px_;
    shared_count<T> pn_;
};

} // namespace MY_DEMO

可以看到这个版本的实现中 shared_ptr 变得更清晰,大部分的工作都交给 shared_count 来做了。

支持多线程

实际上,我们通常会在多线程环境使用 shared_ptr。 为了使我们的 shared_ptr 支持多线程,我们需要在对 sp_count 的 use_count_ 操作变成原子操作。 如果你的编译器支持 C++11 只需要将 sp_count 中的

int use_count_;

改为:

std::atomic_int use_count_;

即可,当然别忘了加上头文件 atomic 。

如果你的编译器不支持 C++11 你需要通过操作系统提供的 API 自己实现原子操作的 use_count_ 。 这里就不一一细说了。