首先,我要声明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. java二维数组学习(转)

    转自:http://blog.csdn.net/java1992/article/details/5808709,在这里谢过了 /* * java学习: * 二维数组的使用: */public cla ...

  2. html5橡皮檫特效

    体验效果:http://keleyi.com/keleyi/phtml/html5/32.htm 效果描述: 有点像刮刮卡一样,在移动设备上,把某张图片刮掉显示出另一张图片.效果图如下: 这种刮图的效 ...

  3. [Kafka] - Kafka内核理解:Message

    一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成 header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成 ...

  4. Log4net 日志记录配置信息

    <log4net> <!--配置日志的级别,低于此级别的就不写到日志里面去 OFF.FATAL.ERROR, WARN, INFO, DEBUG, ALL --> <ro ...

  5. loadrunner测试结果分析

    LR性能测试结果样例分析 测试结果分析 LoadRunner性能测试结果分析是个复杂的过程,通常可以从结果摘要.并发数.平均事务响应时间.每秒点击数.业务成功率.系统资源.网页细分图.Web服务器资源 ...

  6. .Net Core迁移到MSBuild的多平台编译问题

    一.前言 本篇主要讨论.NET Core应用程序项目结构的主题,重点探索.NET Core应用程序的多平台编译问题,这里指的多平台是指.NET Framework..NET Core App..NET ...

  7. 第八讲:I/O虚拟化

    一.I/O虚拟化的产生 服务器单个千兆以太网端口肯定能够支持单个应用,但是当被分割为10个.15个或者更多的服务器负载时(这其中包括网络.存储以及服务器之间的流量)可能就不够用了. 当遇到I/O瓶颈时 ...

  8. 日常:css样式、选择器、个别知识点、数组array

    优先加入css引入文件定义,个别的在下面用style改变.(从左往右,从上往下)CSS样式表1.内联样式表(优先级最高)(改个别的)<div style="width:100px; h ...

  9. 屏幕适配基础——了解:ppi、dpi、px、sp、dp

    做android开发绕不开的几个名词:ppi.dpi.px.sp.dp.那么它们的定义.区别和联系都是什么呢?这篇博客系统的做一个概述和总结. 1.基本概念 px:pixel,像素,电子屏幕上组成一幅 ...

  10. ajax bookstrap美化网页,并实现页面的加载,删除与查看详情

    Bookstrap:美化页面: Bootstrap是Twitter推出的一个开源的用于前端开发的工具包.它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS ...