文档章节

智能指针的实现机理

青灯夜
 青灯夜
发布于 2015/09/01 22:10
字数 1252
阅读 18
收藏 1
  • 介绍

  智能指针是用来实现指针指向的对象的共享的。其实现的基本思想:
  1.每次创建类的新对象时,初始化指针并将引用计数置为1;
  2.当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;
  3.对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数减至0,则删除对象),并增加右操作数所指对象的引用计数;
  4.调用析构函数时,减少引用计数(如果引用计数减至0,则删除基础对象);
  4.重载“->”以及“*”操作符,使得智能指针有类似于普通指针的操作。
  根据以上分析,首先可以得出下面的类模板原型。

template <class T>
class SmartPointer
{
public:

    SmartPointer(T *p = 0);//构造函数
    SmartPointer(const SmartPointer& src);//拷贝构造函数
    SmartPointer& operator = (const SmartPointer& rhs);//赋值函数

    T* operator -> ();//重载->
    T& operator * ();//重载*
    ~SmartPointer();//析构函数

private:

    void MinusRef()
    {
        //被其他成员函数所调用
        if (--*m_pRef == 0)//自身的引用计数减1
        {
            //如果计数为0,则释放内存
            delete m_ptr;

            delete m_pRef;
        }

    }

    T *m_ptr;                           //保存对象指针
    size_t *m_pRef;                     //保存引用计数
};

  上面的私有成员函数MinusRef将引用计数减1。如果引用计数减至0,则删除m_ptr所指对象。根据前面的分析,MinusRef只被赋值函数以及析构函数使用。
下面说明各个成员的具体定义。
  首先是构造函数与析构函数的定义。普通构造函数中,m_ptr与p指向同一块内存,并初始化引用计数为1。拷贝构造函数中与普通构造函数的不同之处为引用计数需要加1。析构函数调用私有成员MinusRef对引用计数递减,并且判断是否需要释放对象。代码如下。

template<class T>
SmartPointer<T>::SmartPointer(T *p)     //普通构造函数
{
    m_ptr = p;                          //m_ptr与p指向同一内存
    m_pRef = new size_t(1);             //m_pRef初值为1
}

template<class T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& src)//拷贝构造函数
{
    m_ptr = src.m_ptr;      //m_ptr与src.m_ptr指向同一内存
    m_pRef++;
    m_pRef = src.m_pRef;    //拷贝引用计数

}

template<class T>
SmartPointer<T>::~SmartPointer()       //析构函数
{
    MinusRef();             //引用减1,如果减后的引用为0,则释放内存
    std::cout<<"SmartPointer: Destructor"<<std::endl;
}

  接下来是“->”和“*”的重载。这两个函数很简单,只需要分别返回m_ptr以及m_ptr所指的内容即可。注意,如果m_ptr此时为空,则应该抛出异常。代码如下。


template<class T>
T* SmartPointer<T>::operator -> ()  //重载 ->
{
    if (m_ptr)
        return m_ptr;

    //m_ptr为NULL时,抛出异常

    throw std::runtime_error("access through NULL pointer");
}
template<class T>
T& SmartPointer<T>::operator * () //重载 *
{
    if (m_ptr)
        return *m_ptr;
    //m_ptr为NULL时,抛出异常

    throw std::runtime_error("dereference of NULL pointer");
}

  最后是赋值函数的实现:

template<class T>

SmartPointer<T>& SmartPointer<T>::operator = (const SmartPointer<T>& rhs)//赋值函数
{
    ++*rhs.m_pRef;      //rhs的引用加1
    MinusRef();         //自身指向的原指针的引用减1
    m_ptr = rhs.m_ptr;  //m_ptr合rhs.m_ptr指向同一个对象
    m_pRef = rhs.m_pRef; //复制引用
    return *this;
}

  这样,就可以像 std::auto_ptr那样来使用SmartPointer。以下先定义一个测试类,测试程序如下。

class Test
{
public:
    Test() {name = NULL;}
    Test(const char* strname)//构造函数
    {
        name = new char[strlen(strname)+1];//分配内存
        strcpy(name, strname);//拷贝字符串
    }
    Test& operator = (const char *namestr)//赋值函数
    {
        if (name != NULL)
        {
            delete name;//释放原来的内存
        }
        name = new char[strlen(namestr)+1];//分配新内存
        strcpy(name, namestr);//拷贝字符串
        return *this;
    }
    void ShowName() {cout << name << endl;}
    ~Test()
    {
        if (name != NULL)
        {
            delete name;
        }
        name = NULL;
        cout << "delete name" << endl;
    }
public:
    char *name;
};

int _tmain(int argc, _TCHAR* argv[])
{
    SmartPointer<Test> t1;//空指针
    SmartPointer<Test> t2(new Test("fefd"));
    SmartPointer<Test> t3(new Test("wewew"));
    try
    {
        t1->ShowName();//空指针调用抛出异常
    }
    catch (const exception& err)
    {
        cout << err.what() << endl;
    }

    t2->ShowName();     //使用t2调用showName()
    *t2 = "David";      //使用t2给对象赋值
    t2->ShowName();     //使用t2调用showName()
    t2 = t3;            //赋值,原来t2的对象引用为0,发生析构
                        //而t3的对象引用加1
    cout << "End of main..." << endl;

    getchar();
    return 0;
}

  main函数代码第41行,t1指向一个NULL指针,因此调用ShowName时会出现异常(异常在重载的“->”函数中被抛出)。
  main函数代码第48~50行,使用SmartPtr对象对Test对象进行操作,其方法与使用Test对象指针的操作方法相同。
  main函数代码第51行,对t2进行赋值操作,操作完成后,t2引用的原对象发生析构(此对象没有SmartPtr对象引用了),t2和t3引用同一个对象,于是这个对象的引用计数加1。注意,这里我们并没有显示地对t2所引用的原对象进行释放操作,这就是智能指针的精髓所在。

版权声明:本文为csdn博主[applebite](http://blog.csdn.net/applebite) 原创文章,转载请注明出处,侵权必究。 微信添加公众号:qi_chuang 或 猎奇创新平台

© 著作权归作者所有

青灯夜
粉丝 2
博文 35
码字总数 21708
作品 0
朝阳
程序员
私信 提问
CAAI成功召开重大科学问题《人类智能的基因调控机理》研讨会

  为配合国家科技发展的重大需求,推进重大科学问题的研究,形成相应的政策建议,中国人工智能学会于10月26日下午在西安锦江国际宾馆国际会议中心召开了“2018年中国科协重大科学问题《人类...

中国人工智能学会
2019/10/27
0
0
学习 LLVM(7) PointerUnion 类

PointerUnion 类当前我知道用在 TinyPtrVector 中做为底层数据存放。简单说明一下。 定义在文件 llvm/include/llvm/[[ADT]]/[[PointerUnion.h]] 中。 == 概述 == 实现联合保存两种不同的可区...

刘军兴
2012/02/28
203
0
科技创新2030---“新一代人工智能”重大项目2018年度项目申报指南征稿

来源:财政资金申请 摘要: “新一代人工智能”重大项目的凝练布局和任务部署已经战略咨询与综合评审特邀委员会咨询评议,并报国务院批准实施。 根据《国务院关于改进加强中央财政科研项目和...

人工智能学家
2018/09/06
0
0
学习 LLVM(6) TinyPtrVector 类

TinyPtrVector.h 位于 llvm/include/llvm/ADT/ 参见:http://llvm.org/docs/ProgrammersManual.html#dsstinyptrvector == 简介 == 模板类 TinyPtrVector<Type> 是一个高度定制的集合类(微型......

刘军兴
2012/02/27
271
0
C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).

目录 C++智能指针,指针容器原理及简单实现(autoptr,scopedptr,ptrvector). autoptr scopedptr ptrvector C++智能指针,指针容器原理及简单实现(autoptr,scopedptr,ptrvector). 前言 最近再写一...

艾露米婭娜
2018/08/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

应急广播户户通平台

一、平台概述 应急广播户户通平台为软硬一体化广播服务解决方案。实现了应急广播、视音频及图片文字信息、调频及数字广播FM、天气预报信息接收功能,以及视音频播放、智能机器人、电子日历等...

neocean
32分钟前
47
0
如何为Apache 2.2启用mod_rewrite

我已经在我的Vista机器上安装了新的Apache 2.2,一切正常,除了mod重写。 我没有注释 LoadModule rewrite_module modules/mod_rewrite.s 但是我的重写规则都没有,即使是简单的重写规则 Re...

javail
38分钟前
23
0
移除Python unicode字符串中的重音符号的最佳方法是什么?

我在Python中有一个Unicode字符串,我想删除所有的重音符号(变音符号)。 我在网上发现了一种用Java实现此目的的优雅方法: 将Unicode字符串转换为长规范化格式(带有单独的字母和变音符号)...

技术盛宴
53分钟前
48
0
ActiveMQ学习之SpringBoot整合ActiveMQ------>主题生产者和消费者

一、pom <!--聚合工程集成关系--> <!--统一整合第三方框架依赖信息--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</a......

冥焱
今天
89
0
两周自制脚本语言-第11天 优化变量读写性能

第11天 优化变量读写性能 以变量值的读写为例,向读者介绍基于这种理念的语言处理器性能优化方式。 11.1 通过简单数组来实现环境 假如函数包含局部变量x与y,程序可以事先将x设为数组的第0个...

果汁分你一半
今天
58
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部