首先,我要声明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 去除 ArrayList 集合中的重复元素

    // One practice package Collection; import java.util.ArrayList; import java.util.Iterator; // 去除 Arr ...

  2. BZOJ [HAOI2011]防线修建(动态凸包)

    听说有一种很高端的东西叫动态凸包维护dp就像学一下,不过介于本人还不会动态凸包就去学了下,还是挺神奇的说,维护上下凸包的写法虽然打得有点多不过也只是维护复制黏贴的事情而已罢了. 先说下动态凸包怎么写吧 ...

  3. 使用JDT.AST解析java源码

    在做java源码的静态代码审计时,最基础的就是对java文件进行解析,从而获取到此java文件的相关信息: 在java文件中所存在的东西很多,很复杂,难以用相关的正则表达式去一一匹配.但是,eclip ...

  4. 学习笔记——Java字符串操作常用方法

    1.创建字符串 最常用的是使用String类的构造方法:String s=new String("abcd"); 也可采用J2SE5.0添加的StringBuilder类的字符串构 ...

  5. 前端学PHP之正则表达式基础语法

    前面的话 正则表达式是用于描述字符排列和匹配模式的一种语法规则.它主要用于字符串的模式分割.匹配.查找及替换操作.在PHP中,正则表达式一般是由正规字符和一些特殊字符(类似于通配符)联合构成的一个文本 ...

  6. spring中对象的注入方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...

  7. 从项目经理的角度看.net的MVC中Razor语法真的很垃圾.

    我们知道,Razor语法中我们可以直接使用@if(){}等代码段,这使得.net程序员在写模版时更容易了. 对比如下: 语法名称 Razor 语法 Web Forms 等效语法 代码块(服务端) @{ ...

  8. RHL 6.0学习日记, 先记下来,以后整理。

    今天又遇到哪些问题呢? 1.配置网络的问题,我把网络配置文件胡乱改了,然后就上不了网了 因为一直都没怎么用到网络,网线都不怎么连接的,今天只是突然想ping一下,于是就Ping 了一下,一开始ping ...

  9. 读书笔记 effective c++ Item 10 让赋值运算符返回指向*this的引用

    一个关于赋值的有趣的事情是你可以将它们链在一起: int x, y, z; x = y = z = ; // chain of assignments 同样有趣的是赋值采用右结合律,所以上面的赋值链被 ...

  10. Sublime Text 3 (Build 3126) 最新注册码

    Sublime Text 作为程序员开发神器,听说最新版更新了 并且增加了不少新特性.马上到官网下载了最新版 Sublime Text 3 3126 使用了下,反应速度比以前的确更快了.随手找了几个S ...