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

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

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

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

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

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

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

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

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

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

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

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

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

//拷贝构造(赋值运算符重载类似,用简洁写法调用拷贝构造即可)
SharedPtr(const SharedPtr &sp)
:_ptr(sp._ptr)
,_count(sp._count){
if(_count!=NULL){
++(*_count);
}
}

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

~SharedPtr(){
if(count!=NULL && *count == 1){
delete _ptr;
delete _count;
_ptr = NULL;
_count = NULL;
}else{
--(*count);
}
}

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

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

/*
*文件说明:模拟实现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;
}

【C++】智能指针简述(四):shared_ptr的更多相关文章

  1. c++11 智能指针 unique_ptr、shared_ptr与weak_ptr

    c++11 智能指针 unique_ptr.shared_ptr与weak_ptr C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer), ...

  2. C++智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr

    手写代码是理解C++的最好办法,以几个例子说明C++四个智能指针的用法,转载请注明出处. 一.auto_ptr auto_ptr这是C++98标准下的智能指针,现在常常已经被C++标准的其他智能指针取 ...

  3. 聊聊智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr

    本文为转载:https://www.cnblogs.com/zeppelin5/p/10083597.html,对作者有些地方做了修正. 手写代码是理解C++的最好办法,以几个例子说明C++四个智能指 ...

  4. C++ 智能指针 auto_ptr 和 shared_ptr

    首先,如果你不知道什么是智能指针,请先移步:C++智能指针简单剖析 1.auto_ptr #ifndef AUTO_PTR_H #define AUTO_PTR_H template<typen ...

  5. c++——智能指针学习(shared_ptr和weak_ptr)

    先看一个例子:Stark和Targaryen家族你中有我,我中有你.我们设计以下类企图避免内存泄漏,使得析构函数都能调用到: #include<iostream> #include< ...

  6. 【C++】智能指针简述(六):智能指针总结及补充

    本文我们主要来总结一下前文介绍过的智能指针相关原理及实现,顺便补充一下前文未提到的shared_ptr删除器部分的内容. 总结: 1.智能指针,通过RAII机制,构造对象时完成资源的初始化,析构对象时 ...

  7. 【C++】智能指针简述(五):解决循环引用的weak_ptr

    总结一下前文内容: 1.智能指针通过RAII方法来管理指针:构造对象时,完成资源初始化;析构对象时,对资源进行清理及汕尾. 2.auto_ptr,通过“转移所有权”来防止析构一块内存多次.(如何转移? ...

  8. 【C++】智能指针简述(三):scoped_ptr

    在介绍scoped_ptr之前,我们先回顾一下前两篇文章的内容. 首先,智能指针采用RAII机制,通过对象来管理指针,构造对象时,完成资源的初始化;析构对象时,对资源进行清理及汕尾. auto_ptr ...

  9. 【C++】智能指针简述(二):auto_ptr

    首先,我要声明auto_ptr是一个坑!auto_ptr是一个坑!auto_ptr是一个坑!重要的事情说三遍!!! 通过上文,我们知道智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析 ...

随机推荐

  1. 『GCD』详解

    2. GCD 任务和队列 学习 GCD 之前,先来了解 GCD 中两个核心概念:任务和队列. 任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码.在 GCD 中是放在 block 中的.执 ...

  2. Spring+Quartz实现定时任务的配置方法(插曲)

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46376093 1.Scheduler的配置 <bean class=&quo ...

  3. VMWare中的Host-only、NAT、Bridge的比較

    VMWare有Host-only(主机模式).NAT(网络地址转换模式)和Bridged(桥接模式)三种工作模式. 1.bridged(桥接模式) 在这样的模式下.VMWare虚拟出来的操作系统就像是 ...

  4. ASP.NET MVC Model之二模型绑定

    Asp.net mvc中的模型绑定,或许大家经常用,但是具体说他是怎么一回事,可能还是会有些陌生,那么,本文就带你理解模型绑定.为了理解模型绑定,本文会先给出其定义,然后对通过比,来得出使用模型绑定的 ...

  5. 前端为啥要用javascript框架

    前端使用EXT.JS,如果存在两个控件,其中A控件的ID 与 B控件的name相同的话,会报错.ID不能存在相同的情况众所周知,而不同的控件,name也不能相同,恐怕只有遇到过的人才知道了,这不,我就 ...

  6. ios29--多线程

    进程是指在系统中正在运行的一个应用程序(一个程序可以对应多个进程).每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内.比如同时打开迅雷.Xcode,系统就会分别启动2个进程.1个进程要 ...

  7. Android 修改开机动画(bootanimation)【转】

    本文转载自:http://blog.csdn.net/u012301841/article/details/51598115 Android 系统自带的开机动画,是一个白色的 “android” 文字 ...

  8. javaSE基础(二)

    文件:文件是信息在计算机上的保存形式. 可控式异常:一种必须被处理或必须在可能产生异常的方法中给出声明的异常. 可控式异常的三种处理方式: 1)try...catch捕获 2)throws语句往上抛 ...

  9. C# winfrom TCP 服务端和客户端(链接)

    1.C#Winform TCP 之服务端: 可以参考下面链接,比较好.第二个链接可以看看,提供了一个思路. http://www.cnblogs.com/guolebin7/archive/2013/ ...

  10. rsync单向同步

    系统版本:Centos X64 6.4(最小化安装) 先安装依赖包 [root@localhost ~]# yum install vim wget lsof gcc make cmake makec ...