首先,我要声明auto_ptr是一个坑!auto_ptr是一个坑!auto_ptr是一个坑!重要的事情说三遍!!!

  通过上文,我们知道智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析构对象时完成资源的清理及汕尾工作.

  因此,可以得到一份简洁版的智能指针代码:

template<typename T>
class AutoPtr{
public:
//构造函数,完成资源的初始化与分配
AutoPtr(T * ptr = NULL)
:_ptr(ptr){}
//析构函数,完成资源的清理及汕尾工作
~AutoPtr(){
if(_ptr!=NULL){
delete _ptr;
_ptr = NULL;
}
}
private:
T *_ptr;
};

  大致一看,没毛病!突然觉得自己无所不能,感觉自己就是传说中的编程天才!

  可是,如果我想这样的话.....:

AutoPtr<int> ap1(new int(100));
AutoPtr<int> ap2(new int(200));
AutoPtr<int> ap3(ap1);
AutoPtr<int> ap4();
ap4 = ap2;

  ap1与ap3共同管理一块空间;ap2与ap4共同管理一块空间,看起来好像没什么问题.

  但当程序跑起来,出了函数作用域之后....崩毁了!!?

  ......Why?

  好在我经验丰富,见多识广,脑袋回路中很自然地想起了类似的情况:string类的浅拷贝....

  因此,机智的我立刻发现了原因:由于没有定义拷贝构造函数与赋值运算符重载,那么在拷贝构造对象和给对象赋值时,系统会默认生成相应函数.

  ap1与ap3共同管理一块空间,一旦出了函数作用域,ap3会调用析构函数,delete掉所指向的空间;

  而当ap1调用析构函数时,此时ap1所指向的已经是一块非法内存(因为被ap3 delete过了),因此当ap1再次delete这块空间时,程序挂掉了!

  简而言之:同样一块空间被delete了两次,所以最终程序挂掉了!

  那么我就好奇了,auto_ptr如何应对拷贝与赋值的呢?

  在百度了各种资料及阅读其源代码之后,发现auto_ptr是这么处理的:

//拷贝构造
AutoPtr(AutoPtr& ap){
//转移管理权
_ptr = ap._ptr;
ap._ptr = NULL;
}
//赋值运算符重载
AutoPtr &operator=(AutoPtr &ap){
if(ap._ptr != _ptr){
AutoPtr tmp(ap);
std::swap(_ptr,tmp._ptr);
}//由析构函数去管理tmp
return *this;
}

  这是我简化后的代码,再次应对上述情况时:

AutoPtr<int> ap1(new int(100));
AutoPtr<int> ap2(new int(200));
AutoPtr<int> ap3(ap1);  //ap3 = NULL
AutoPtr<int> ap4();
ap4 = ap2;         //ap2 = NULL

  我们发现:auto_ptr通过转移管理权,来保证在赋值与拷贝时仅管理一份指针,而防止同一块空间释放多次的问题.

  最后,我将自己写的简洁、精简、易读的AutoPtr与库中的代码一起贴上来

/*
*文件说明:智能指针之AutoPtr
*作者:高小调
*日期:2017-03-30
*集成开发环境:Microsoft Visual Studio 2010
*Github:https://github.com/gaoxiaodiao/c_cplusplus/blob/master/SmartPointer/AutoPtr.h
*/
#pragma once
template<typename T>
class AutoPtr{
public:
//构造函数
AutoPtr(T * ptr = NULL)
:_ptr(ptr){}
//拷贝构造
AutoPtr(AutoPtr& ap){
//转移管理权
_ptr = ap._ptr;
ap._ptr = NULL;
}
//赋值运算符重载
AutoPtr &operator=(AutoPtr &ap){
if(ap._ptr != _ptr){
AutoPtr tmp(ap);
std::swap(_ptr,tmp._ptr);
}//由析构函数去管理tmp
return *this;
}
//析构函数
~AutoPtr(){
if(_ptr!=NULL){
delete _ptr;
_ptr = NULL;
}
}
private:
T *_ptr;
}; void TestAutoPtr(){
AutoPtr<int> ap1(new int(100));
AutoPtr<int> ap2(new int(200));
AutoPtr<int> ap3(ap1);
AutoPtr<int> ap4(ap2);
ap3 = ap4;
}

  库内实现(我就懒得写注释了,看完精简版后,再看库中实现会发现库内的封装性、代码复用性更高一些)

template<class T>
class auto_ptr
{
private:
T*ap;
public:
//constructor & destructor-----------------------------------(1)
explicit auto_ptr(T*ptr=0)throw():ap(ptr)
{
} ~auto_ptr()throw()
{
delete ap;
}
//Copy & assignment--------------------------------------------(2)
auto_ptr(auto_ptr& rhs)throw():ap(rhs.release())
{
}
template<class Y>
auto_ptr(auto_ptr<Y>&rhs)throw():ap(rhs.release())
{
}
auto_ptr& operator=(auto_ptr&rhs)throw()
{
reset(rhs.release());
return *this;
}
template<class Y>
auto_ptr& operator=(auto_ptr<Y>&rhs)throw()
{
reset(rhs.release());
return *this;
}
//Dereference----------------------------------------------------(3)
T& operator*()const throw()
{
return *ap;
}
T* operator->()const throw()
{
return ap;
}
//Helper functions------------------------------------------------(4)
//value access
T* get()const throw()
{
return ap;
}
//release owner ship
T* release()throw()
{
T*tmp(ap);
ap=0;
return tmp;
}
//reset value
void reset(T*ptr=0)throw()
{
if(ap!=ptr)
{
deleteap;
ap=ptr;
}
}
//Special conversions-----------------------------------------------(5)
template<class Y>
struct auto_ptr_ref
{
Y*yp;
auto_ptr_ref(Y*rhs):yp(rhs){}
};
auto_ptr(auto_ptr_ref<T>rhs)throw():ap(rhs.yp)
{
} auto_ptr& operator=(auto_ptr_ref<T>rhs)throw()
{
reset(rhs.yp);
return*this;
} template<class Y>
operator auto_ptr_ref<Y>()throw()
{
returnauto_ptr_ref<Y>(release());
} template<class Y>
operator auto_ptr<Y>()throw()
{
returnauto_ptr<Y>(release());
}
};

  与君共勉!

【C++】智能指针详解(二):auto_ptr的更多相关文章

  1. 【C++】智能指针详解(一):智能指针的引入

    智能指针是C++中一种利用RAII机制(后面解释),通过对象来管理指针的一种方式. 在C++中,动态开辟的内存需要我们自己去维护,在出函数作用域或程序异常退出之前,我们必须手动释放掉它,否则的话就会引 ...

  2. [转]C++ 智能指针详解

    转自:http://blog.csdn.net/xt_xiaotian/article/details/5714477 C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每 ...

  3. C++ 智能指针详解(转)

    C++ 智能指针详解   一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常 ...

  4. 【C++】智能指针详解

    转自:https://blog.csdn.net/flowing_wind/article/details/81301001 参考资料:<C++ Primer中文版 第五版>我们知道除了静 ...

  5. C++智能指针详解

    本文出自http://mxdxm.iteye.com/ 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最 ...

  6. 【转】C++ 智能指针详解

    一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 ...

  7. [C++11新特性] 智能指针详解

    动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极为困难的.有时我们会忘记释放内存产生内存泄漏,有时提前释放了内存,再使用指针去引用内存就会报错. 为了更容易(同时也更安全)地使用动态内存, ...

  8. C++11 unique_ptr智能指针详解

    在<C++11 shared_ptr智能指针>的基础上,本节继续讲解 C++11 标准提供的另一种智能指针,即 unique_ptr 智能指针. 作为智能指针的一种,unique_ptr ...

  9. c/c++指针详解(一)

    一:相关概念 1.指针数组:int *p[6]               是数组,是一个存放指针的数组,也就是里面存放的是地址. 2.数组指针:int (*p)[6]                 ...

随机推荐

  1. .Net程序员学用Oracle系列(17):数据库管理工具(SQL Plus)

    1.数据库管理工具概述 2.SQL Plus 实用命令参考 2.1.连接/断开命令 2.2.执行 SQL 语句 2.3.执行 PL/SQL 语句 2.4.文件操作命令 2.5.修改用户密码 2.6.执 ...

  2. web开发之Servlet 一

    因为最近在研究公司一套新的框架,发现这套框架的底层是对Struts2,Spring 封装后的WEB应用框架,而我发现如果仅仅是利用这个框架开发,确实很容易快速上手,做业务来说是没有问题的,但我觉得如果 ...

  3. BZOJ 2424: [HAOI2010]订货(费用流)

    裸的费用流了= =从源点向每个点连费用为di,从汇点向每个点连流量为ui,每个点向下一个点连费用为m,流量为s的边就行了 CODE: #include<cstdio>#include< ...

  4. 安装MongoDB x86_64

    1.下载MongoDB 下载mongodb的windows版本,有32位和64位版本,根据系统情况下载,下载地址:http://www.mongodb.org/downloads 2.安装MongoD ...

  5. jeesite简单入口分析

    这两天要开新项目 , 准备使用比较受欢迎的 jeesite框架 . jeesite是一个写好的网站 , 用到的框架比较多 具体请看 -- > github链接 下载下来之后 , 手动把maven ...

  6. Linux 内存优化

    1.清理前内存使用情况 free -m2.开始清理   echo 1 > /proc/sys/vm/drop_caches 3.清理后内存使用情况 free -m 4.完成! 查看内存条数命令: ...

  7. SQLHelper帮助类_下(支持多数据库的封装)

    在上篇关于SQLHelper类中,主要针对SQLServer数据库进行的.在使用别的数据库,就要修改部分代码!所以今天就写一个支持多数据库的封装!主要用到枚举,读取config文件!接口的简单用法.获 ...

  8. 做了个新的UWP类库 Sharp2D

    C#开发UWP的时候如果要实现高斯模糊效果的话,最好的选择似乎是微软的Win2D 但是Win2D太过庞大了,仅仅是庞大其实也没啥问题,毕竟net core就很庞大,但Win2d是一个Winmd组件 w ...

  9. nodejs第二天之Buffer类

    2.1一个更好的操作二进制数据的类,我们在操作文件或者网络数据的时候,其实操作就是二进制数据,Node为我们提供了一个更加方便去操作这种数据流的类Buffer,它是一个全局的类. 2.2三种调用方式 ...

  10. android 仿摩拜单车共享单车进度条实现StepView

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6552712.html 先看效果图: Step1:定义StepBean 定义五个状态,分别为:为完成.正在进行 ...