凌云的博客

行胜于言

漫谈 C++ 智能指针 03

分类:c++| 发布时间:2015-09-24 10:32:00


模拟原始指针的行为

在第一篇文章我们说过智能指针会通过重载某些运算符来模拟普通指针的行为。 在本文中我们来看看智能指针一般需要重载哪些运算符以及其应用场景。

重载 operator!

对于原始指针我们常用的操作就是判断这个指针是否是空指针。

bool check_ptr(int *p)
{
    return !p;
}

对于智能指针,在没有重载这个操作符之前我们需要如下判断其原始指针是否为空:

bool check_smart_ptr(smart_ptr<int> p)
{
    return !p.get();
}

颇为麻烦!通过重载 operator! 可以简化这一操作

```cpp
template<typename T>
class smart_ptr
{
public:
    explicit smart_ptr(T *p = 0): p_(p) {}
    ~smart_ptr() {
        clean();
    }

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

        clean();
        p_ = p;
    }

    T* get() {
        return p_;
    }

    T* release() {
        T* tmp = p_;
        p_ = 0;
        return tmp;
    }

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

    void clean() {
        if (p_) {
            delete p_;
            p_ = 0;
        }
    }
private:
    T *p_;
};

bool check_smart_ptr(smart_ptr<int> p)
{
    return !p;
}

可以看到,通过重载 operator! 我们可以像对待原始指针那样对智能指针进行判断。

重载 operator*

首先我们来看看上篇文章中的例子:

int *make_int()
{
    int *tmp = new int(3);
    if (!tmp)
        return 0;

    if (failed)
        return 0;

    return tmp;
}

bool some_func()
{
    smart_ptr<int> int_p(make_int());
    if (!int_p)
        return false;

    // set int to 4
    (*int_p.get()) = 4;
    return true;
}

注意 (*int_p.get()) = 4; 首先要用 get() 取出 int_p 所拥有的普通指针然后对其进行解引用, 最后才将 4 赋值给 int_p 所拥有的普通指针。 如果能够像普通指针那样 *int_p = 4; 那样对智能指针进行赋值就好了。 通过重载 operator* 可以做到这一点:

template<typename T>
class smart_ptr
{
public:
    // See other impl above

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

private:
    T *p_;
};

bool some_func()
{
    smart_ptr<int> int_p(make_int());
    if (!int_p)
        return false;

    // set int to 4
    *int_p = 4;
    return true;
}

重载 operator->

首先来看个例子:

struct some_type {
    int a_int;
    float b_float;
};

some_type *make_some_type()
{
    some_type *tmp = new some_type();
    if (!tmp)
        return 0;

    if (failed)
        return 0;

    return tmp;
}

bool some_func()
{
    smart_ptr<some_type> some_type_p(make_some_type());
    if (!some_type_p)
        return false;

    // set a_int field to 4
    // set b_float field to 8.0
    some_type_p.get()->a_int = 4;
    some_type_p.get()->b_float = 8.0;
    return true;
};

可以看到设置 some_type 的成员时要先取出其原始指针,然后再赋值。 通过重载 operator-> 可以将智能指针看成原始指针,直接对其成员变量进行赋值。

template<typename T>
class smart_ptr
{
public:
    // See other impl above

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

private:
    T *p_;
};

bool some_func()
{
    smart_ptr<some_type> some_type_p(make_some_type());
    if (!some_type_p)
        return false;

    // set a_int field to 4
    // set b_float field to 8.0
    some_type_p->a_int = 4;
    some_type_p->b_float = 8.0;
    return true;
}

总结

通过重载智能指针的的 operator! operator* 以及 operator-> 等运算符, 可以将很多用于原始指针的操作直接作用于智能指针。 使得我们通过智能指针来获得资源管理的特性的同时, 又可以在很大程度上让我们像使用普通指针一样使用智能指针。