博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【C++】智能指针简述(四):shared_ptr
阅读量:6443 次
发布时间:2019-06-23

本文共 2339 字,大约阅读时间需要 7 分钟。

hot3.png

  在开始本文内容之前,我们再来总结一下,前文内容:

  1.智能指针采用RAII机制,在构造对象时进行资源的初始化,析构对象时进行资源的清理及汕尾.

  2.auto_ptr防止拷贝后析构释放同一块内存,采用"转移所有权"的方法.(实际开发中auto_ptr并不实用)

  3.scoped_ptr与auto_ptr类似,但是它与auto_ptr最大的区别是:它不能转移所有权,即就是禁止拷贝/赋值!(当然,我们也探讨了C++中禁止拷贝对象的技术,在此不赘述)

  回顾完前文内容后,我们今天来讨论shared_ptr.

  我们虽然有了scoped_ptr,但在实际开发过程中,我们的确要是想对智能指针进行拷贝,那scoped_ptr就鞭长莫及了.

  那么,我们回到原始的问题:对智能指针进行拷贝,会出现什么情况?

  我们在第二篇文章也分析了:如果对智能指针不进行特殊处理,在析构时,会将同一块内存释放多次,程序会崩溃!

  因此,我们要想对智能指针进行拷贝,就必须做一些特殊的处理,使得析构函数只释放一次内存.

  此时,如果探究过深浅拷贝的同学,可能心中已经有了答案:用引用计数!!!(深浅拷贝问题,以后我会讨论,不是本文重点)

  考虑到有些童鞋可能不知道什么是引用计数,那我就在这里解释一下:

  在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。——百度百科

  通俗一点的讲:在本例中我们通过count变量来记录当前有多少个对象共同维护着这个指针,每次拷贝/赋值的时候,让count++.

1

2

3

4

5

6

7

8

//拷贝构造(赋值运算符重载类似,用简洁写法调用拷贝构造即可)

SharedPtr(const SharedPtr &sp)

    :_ptr(sp._ptr)

    ,_count(sp._count){

        if(_count!=NULL){

            ++(*_count);

        }

}

  当对象析构时,首先我们看count是不是1,如果不是1,说明还有其他对象在维护这个指针,我们让count--.否则的话,就说明,只有当前对象在维护这个指针,此时就可以愉快的把指针delete掉了.

1

2

3

4

5

6

7

8

9

10

~SharedPtr(){

    if(count!=NULL && *count == 1){

        delete _ptr;

        delete _count;

        _ptr = NULL;

        _count = NULL;

    }else{

        --(*count);

    }

}

  通过这样的的形式,就可以保证:在多个shared_ptr对象共同维护一块内存中,对内存只delete一次.

  最终,贴上我简化后shared_ptr的代码.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

/*

*文件说明:模拟实现shared_ptr

*作者:高小调

*日期:2017-03-31

*集成开发环境:Microsoft Visual Studio 2010

*/

#pragma once

template<typename T>

class SharedPtr{

public:

    //构造函数

    SharedPtr(T *ptr=NULL)

        :_ptr(ptr)

        ,_count(NULL){

            if(ptr!=NULL){

                _count = new int(1);

                std::cout<<_ptr<<" Is Created"<<std::endl;

            }

    }

    //拷贝构造

    SharedPtr(const SharedPtr & sp)

        :_ptr(sp._ptr)

        ,_count(sp._count){

            if(sp._count!=NULL){

                ++(*_count);

            }

    }

    //赋值运算符重载

    SharedPtr& operator=(const SharedPtr &sp){

        if(_ptr!=sp._ptr){

            SharedPtr tmp(sp);

            std::swap(_ptr,tmp._ptr);

            std::swap(_count,tmp._count);

        }

        return *this;

    }

    //析构函数

    ~SharedPtr(){

        if(_count!=NULL && --(*_count)==0){

            std::cout<<_ptr<<" Is Destory"<<std::endl;

            delete _ptr;

            delete _count;

            _ptr = NULL;

            _count = NULL;

        }

    }

private:

    T* _ptr;

    int *_count;

};

 

void TestSharedPtr(){

    SharedPtr<int> sp1(new int(10));

    SharedPtr<int> sp2(new int(20));

    SharedPtr<int> sp3(new int(30));

    SharedPtr<int> sp4(sp1);

    sp2 = sp1;

    sp3 = sp1;

}

转载于:https://my.oschina.net/u/4000302/blog/3024235

你可能感兴趣的文章
python类型转换、数值操作(收藏)
查看>>
mysql delimiter
查看>>
关于C#静态构造函数的几点说明
查看>>
理解C# 4 dynamic(4) – 让人惊艳的Clay
查看>>
管理-职业化沟通
查看>>
angular之$compile
查看>>
SQL中Truncate的用法
查看>>
一键安装docker-ce
查看>>
彻底理解Netty,这一篇文章就够了
查看>>
极光开发者沙龙 JIGUANG MEETUP —— 移动应用性能优化实践
查看>>
最新的CocoaPods安装步骤 pod install/pod update更新慢等问题
查看>>
高并发下的一些问题
查看>>
如何为Django添加中文搜索服务
查看>>
Spring Cloud Config 统一配置中心
查看>>
Java获取文本文件字符编码的两种方法
查看>>
js数据类型只string,object
查看>>
android httpClient(https/http)的优化构建方式二
查看>>
架设用Webservice实现文件上传功能CentOS服务器(一)--Tomcat
查看>>
一步一步部署Laravel项目
查看>>
.net 2.0 4.0 表单中危险字符
查看>>