浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第28课 再论智能指针(下)

Posted on 2017-06-25 16:01  浅墨浓香  阅读(236)  评论(0编辑  收藏  举报

1. SharedPointer的设计

(1)使用类模板,通过计数机制标识堆内存

(2)堆内存被指向时,(*refCount)++

(3)指针被置空时:(*refCount)—

(4)当*refCount == 0时,释放堆内存

2. 计数机制原理剖析

 

3. SharedPointer类的声明

template <typename T>
class SharedPointer : public Pointer<T>
{
protected:
    int* m_refCount; //计数机制成员
public:
    SharedPointer(T* p = NULL);
    SharedPointer(const SharedPointer<T>& obj);
    
    SharedPointer<T>& operator=(const SharedPointer<T>& obj);
    
    void clear(); //将当前指针置为空
    
    //由于SharedPointer支持多个对象同时指向一片堆空间
    //因此必须支持比较操作!
    bool operator==(const SharedPointer<T>& obj);
    bool operator!=(const SharedPointer<T>& obj);
    
    ~SharedPointer();
};

4. 智能指针使用军规

(1)只能用来指向堆空间中的单个对象(变量)

(2)不同类型的智能指针对象不能混合使用

(3)不要使用delete释放智能指针指向的堆空间

【编程实验】SharedPointer智能指针的实现

//Pointer.h

#ifndef _POINTER_H_
#define _POINTER_H_

#include "Object.h"

namespace DTLib {

template <typename T>
class Pointer : public Object //Object是析构函数本身是纯虚函数!
{
protected:
    T* m_pointer;
public:
    Pointer(T* p = NULL)
    {
        m_pointer = p;
    }

    T* operator->()
    {
        return m_pointer;
    }

    T& operator*()
    {
        return *m_pointer;
    }

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

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

    bool isNull() const
    {
        return (m_pointer == NULL);
    }

    T* get() const
    {
        return m_pointer;
    }
};

}

#endif // _POINTER_H_

//SharedPointer.h

#ifndef _SHAREDPOINTER_H_
#define _SHAREDPOINTER_H_

#include "Pointer.h"
#include "exception.h"
#include <cstdlib>

namespace DTLib
{
template <typename T>
class SharedPointer : public Pointer <T>
{
protected:
    int * m_ref;

    void assign(const SharedPointer<T> &obj)
    {    //复制
        this->m_ref = obj.m_ref;
        this->m_pointer = obj.m_pointer; //指向后者的堆内存

        if (this->m_ref)
        {       //如果指向了合法的指针变量
            (*this->m_ref)++; //计数加1
        }
    }
public:
    SharedPointer(T *p = NULL) : m_ref(NULL)
    {
        if (p)
        {    //堆空间中申请4个字节的空间
//
注意此处不用new,因为int是基本类型不是Object的子类,也就无法享受Object类中重载new的好处,即new int失败时,由于编译器处理方式不同,仍可能是NULL或抛异常。为了统一处理,用malloc
            this->m_ref = static_cast<int*>(malloc(sizeof(int)));

            if (this->m_ref)
            {
                *(this->m_ref) = 1;    //初始化1 ,说明p的堆空间已经有一个sharedpointer指针指向了
                this->m_pointer = p;
            }
            else
            {    //若malloc不成功,抛出异常
                THROW_EXCEPTION(NotEnoughMemoryException, "No memory to create SharedPointer object ... ");
            }
        }
    }

    SharedPointer(const SharedPointer<T> &obj) : Pointer<T>(NULL)
    { //拷贝构造函数
        assign(obj);
    }

    SharedPointer<T> &operator =(const SharedPointer<T> &obj)
    {
        if (this != &obj)
        {    //避免自赋值
            clear(); //  如果当前的sharepointer指针已经指向 另外一片堆空间,
            //应该先置空当前指针,不让它指向任何堆空间
            assign(obj);
        }

        return *this;
    }

    void clear()
    { //置空函数
        T *toDel = this->m_pointer;
        int *ref = this->m_ref;

        this->m_pointer = NULL;
        this->m_ref = NULL;

        if (ref)
        { //如果ref不为空指针
            (*ref)--;//释放一个指针减1

            if (*ref == 0) //若堆空间没有对应的指针指向
            {
                free(ref);

                delete toDel;
            }
        }
    }
    //由于SharedPointer支持多个对象同时指向一片堆空间。因此必须支持比较操作!
    bool operator==(const SharedPointer<T>& obj)
    {
        return (this->m_pointer == obj.m_pointer);
    }

    bool operator!=(const SharedPointer<T>& obj)
    {
        return (this->m_pointer != obj.m_pointer);
    }

    ~SharedPointer()
    {
        clear();
    }
};

}
#endif // _SHAREDPOINTER_H_

//main.cpp

#include <iostream>
#include "SharedPointer.h"

using namespace std;
using namespace DTLib;

class Test : public Object
{
public:
    int value;

    Test(): value(0)
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout <<"~Test()" << endl;
    }
};

int main()
{
    //const SharedPointer<Test> sp0 = new Test();
    SharedPointer<Test> sp0 = new Test();
    SharedPointer<Test> sp1 = sp0;
    SharedPointer<Test> sp2 = NULL;

    sp2 = sp1;

    sp0->value = 100;

    cout << sp0->value << endl;
    cout << sp1->value << endl;
    cout << sp2->value << endl;

    //sp1.clear();

    cout << (sp0==sp1) << endl;

    return 0;
}
/*输出结果
Test()
100
100
100
1
~Test()
*/

5. 小结

(1)SharedPointer最大程度的模拟了原生指针的行为

(2)计数机制确保多个智能指针合法的指向同一片堆空间

(3)智能指针只能用于指向堆空间中的内存

(4)不同类型的智能指针不要混合使用

(5)堆对象的生命周期由智能指针进行管理