智能指针

一直都知道智能指针是依靠引用计数的原理实现的,但是,自己一直都没有尝试自己实现一个简单的指针指针,最近尝试自己写了一个智能指针的类,进行了简单的测试,不知道会不会有bug,代码如下:

SmartPointer.h

#include <iostream>

template <typename T>

class SmartPointer
{
    public:
    //构造函数
    SmartPointer( T *p = 0 ):_ptr( p ), _reference_count ( new size_t ){
        if( p )
            *_reference_count = 1;
        else
            *_reference_count = 0;
    }

    //拷贝构造函数(浅拷贝)
    SmartPointer( const SmartPointer& other )
    {
        if( this != &other )
        {
            _ptr = other._ptr;
            _reference_count = other._reference_count;
            (* _reference_count )++;
        }
    }

    //重载赋值操作符
    SmartPointer& operator= ( const SmartPointer& other )
    {
        if( _ptr == other._ptr )
            return *this;
        //先释放原有所指向的对象
        releaseCount();

        _ptr = other._ptr;
        _reference_count = other._reference_count;
        //增加引用计数
        ( * _reference_count )++;
        return *this;
    }

    //重载运算符
    T& operator*()
    {
        if( _ptr )
            return *_ptr;
    }
    //重载运算符
    T* operator->()
    {
        if( _ptr )
            return _ptr;
    }
    //析构函数
    ~SmartPointer()
    {
        if( -- ( *_reference_count )  == 0 )
        {
            delete _ptr;
            delete _reference_count;
        }
    }
    private:
        T *_ptr;
        size_t *_reference_count;//指针
        void releaseCount(){
            if( _ptr  )
            {
                (* _reference_count )--;
                if( (*_reference_count) == 0 )
                {
                    delete _ptr;
                    delete _reference_count;
                }
            }
        }
};

再介绍一下常用的智能指针:
1. std::auto_ptr,有很多问题。 不支持复制(拷贝构造函数)和赋值(operator =),但复制或赋值的时候不会提示出错。因为不能被复制,所以不能被放入容器中。
2. C++11或boost的shared_ptr,基于引用计数的智能指针。可随意赋值,直到内存的引用计数为0的时候这个内存会被释放。
3. C++11或boost的weak_ptr,弱引用。 引用计数有一个问题就是互相引用形成环,这样两个指针指向的内存都无法释放。需要手动打破循环引用或使用weak_ptr。顾名思义,weak_ptr是一个弱引用,只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检查weak_ptr是否为空指针。
4. C++11引入的unique_ptr, 也不支持复制和赋值,但比auto_ptr好,直接赋值会编译出错。实在想赋值的话,需要使用std::move。
例如:

std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; // 编译会出错
std::unique_ptr<int> p3 = std::move(p1); // 转移所有权, 现在那块内存归p3所有, p1成为无效的指针.

谈到智能指针互相引用成环的问题,下面举个例子:

class B;
class A
{
public:
  shared_ptr<B>
 m_b;
};

class B
{
public:
  shared_ptr<A>
 m_a;
};

int main()
{
  while (true)
  {
    shared_ptr<A>
 a(new A);
//new出来的A的引用计数此时为1
    shared_ptr<B>
 b(new B);
//new出来的B的引用计数此时为1
    a->m_b
 = b; //B的引用计数增加为2
    b->m_a
 = a; //A的引用计数增加为2
  }

  //b先出作用域,B的引用计数减少为1,不为0,所以堆上的B空间没有被释放,且B持有的A也没有机会被析构,A的引用计数也完全没减少

  //a后出作用域,同理A的引用计数减少为1,不为0,所以堆上A的空间也没有被释放

}

所以在使用基于引用计数的智能指针时,要特别小心循环引用带来的内存泄漏,循环引用不只是两方的情况,只要引用链成环都会出现问题。当然循环引用本身就说明设计上可能存在一些问题,如果特殊原因不得不使用循环引用,那可以让引用链上的一方持用普通指针(或弱智能指针weak_ptr)即可

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值