智能指针(一):STL auto_ptr实现原理
智能指针实际上是一个类(class),里面封装了一个指针.它的用处是啥呢?
指针与内存
说到指针自然涉及到内存.我们如果是在堆栈(stack)中分配了内存,用完后由系统去负责释放.如果是自定义类型,就会自动的去调用你的析构函数.
但如果是在堆(heap)中分配了内存,也就是用malloc或者new.那只能自动手动的使用free或delete去释放.所以使用heap时处理的不好很容易出现啥内存泄露(内存没有释放掉).或者如果你delete一次了,但没让它赋值为0,然后再delete一次就导致未定义行为了.
于是你想如果系统能也像管理stack一样来管理你的heap区域.不用再担心内存的分配与释放该多好啊.事实上Java,C#都这样去做了.也给你去管理heap区域了(所有的自定义类型实例化时都去heap区域获取内存了.也没于提供指针的功能.你想自己去释放内存都不给你这机会了.JVM或者CLR会在后台自动的去给你释放掉那些不用的内存.当然这样一来效率自然没有你手动释放来的高了.)
假如有一个指针指向一块分配的内存,智能指针就是把该指针封装起来,然后用完了会自动去释放内存(通过智能指针类的析构函数).这样你就不用担心没有去释放内存了.当然并不是说你使用了智能指针就能像使用Java,C#一样不用再担心内存问题了.智能指针在使用的时候还会存在很多的问题.
据说JVM,CRL也是用(c与c++)实现的.不知道那里面也有用到智能指针不.
智能指针的实现
如果你自己要封装一个指针你会咋整呢?来来个初稿瞧瞧
1.最精简版本
template< class T>
class my_auto_ptr {
public:
T* m_ptr; //被封装的指针
public:
my_auto_ptr( T* p) :m_ptr( p ) { } //构造函数
~my_auto_ptr() { delete m_ptr; } //析构函数
}
上面的自然是最精简版的,只一个成员变量,构造函数和析造函数.不过虽然简单其实也能拿来用了啊.比如:
my_auto_ptr<int> myPtr( new int(88) ); //等价int* ip = new int(88); 但这样你得手动delete ip;而用了智能指针就不用手动delete了.
cout<< *myPtr.m_ptr; //相当于cout<<*ip;
2.改进版本(重载运算符使类用起来像指针)
上面的的精简版本用起来还挺麻烦.我们是希望封装了指针类用起来跟指针本身一样才好.所以需要重载-> , * 等运算符
template< class T>
class my_auto_ptr {
private:
T* m_ptr; //被封装的指针
public:
my_auto_ptr( T* p) :m_ptr( p ) { }
~my_auto_ptr() { delete m_ptr; }
T& operator*() { return *m_ptr;}
T* operator->() { return m_ptr;}
}
现在my_auto_ptr可以变得很像指针了
my_auto_ptr<int> mp(new int(88) ); //等价int* ip = new int(88);
int num = *mp; //等价int num = *ip;
假如有这样的类struct Arwen { void Test() { cout<"i am arwen"<<; }
则my_auto_ptr<Arwen> mp( new Arwen); //等价Arwen* ip = new Arwen;
mp->Test(); //等价ip-Test();
3.完善版本(复制构造)
一个完善点的类往往还涉及到复制构造的一些操作.也可以做把另外一个智能指针类做为构造函数的参数,或者通过=给一个类赋值
template< class T>
class my_auto_ptr {
private:
T* m_ptr;
T* GetPtr(){ //供构造赋值时使用
T* tmp = m_ptr;
m_ptr = 0;
return tmp;
}
public:
explicit my_auto_ptr( T* p = 0) :m_ptr( p ) { }
~my_auto_ptr() { delete m_ptr; }
T& operator*() { return *m_ptr;}
T* operator->() { return m_ptr;}
my_auto_ptr(my_auto_ptr& mp){ //复制构造函数
m_ptr = mp.GetPtr(); //mp复制过来后它自己原来的指针相当于失效了.
}
my_auto_ptr& operator=(my_auto_ptr& ap){ 造型赋值操作符
if(ap != *this)
{
delete m_ptr;
m_ptr = ap.GetPtr();
}
return *this;
}
void reset(T* p){ //指针重置,相当于把指针指向另外一个地方去
if(p != m_ptr)
delete m_ptr;
m_ptr = p;
}
};
使用举例:
假如有类struct Arwen{
int age;
Arwen(int gg) :age(gg) { };
};
void main()
{
my_auto_ptr<Arwen> myPtr( new Arwen(24) );
int num =myPtr->age; //正确
my_auto_ptr<Arwen> ptrOne( myPtr); //复制构造
//num =myPtr->age; 该处会出错.因为把myPtr复制给ptrOne后,它自己本身相当于失效了
num = ptrOne->age; //正确
my_auto_ptr<Arwen> ptrTwo = ptrOne;
//num = ptrOne->age;该处也会出错,此时ptrOne也失效了
num = ptrTwo->age; //正确
Arwen* pArwen = new Arwen( 88 );
ptrTwo.reset( pArwen);
num = pArwen->age; //此处的值是88了,而不是以前的24
return 0;
}
auto_ptr的缺陷
上面我实现的my_auto_ptr基本上是实现了auto_ptr的所有核心功能.从里面我们可以明显的看到一个很大缺陷.我们看到当通过复构造函数,通过操作符=赋值后,原来的那个智能指针对象就失效了.只有新的智能指针对象可以有效使用了.用个专业点的说法叫所有权的转移.被包装的指针指向的内存块就像是一份独享占用的财产,当通过复制构造,通过=赋值传给别的智能指针对象时,原有的对象就失去了对那块内存区域的拥有权.也就是说任何时候只能有一个智能指针对象指向那块内存区域,不能有两个对象同时指向那块内存区域.
这样一来auto_ptr不能做为STL中容器的元素,为啥呢? 因为容器中经常存在值拷贝的情况嘛,把一个容器对象直接赋值给另一对象.完了之后两个容器对象可得都能用啊.而如果是auto_ptr的话显然赋值后只能一个有用,另一个完全报废了.另外比如你有个变量auto_ptr<int> ap( new int(44) ); 然后ap被放进一个容器后,ap就报废不能用了.
不过没办法啊,在c++ 11标准之前,现在我们大部分用的是98标准吧,STL里面只有auto_ptr这一种智能指针.而在11标准中除了auto_ptr还有如下三种:
unique_ptr
smart pointer with unique object ownership semantics
只能有一个主人的指针,可以用于STL容器
shared_ptr
smart pointer with shared object ownership semantics
可共享的指针
weak_ptr
weak reference to an object managed by std::shared_ptr
弱引用指针
智能指针(一):STL auto_ptr实现原理的更多相关文章
- 【校招面试 之 C/C++】第25题 C++ 智能指针(一)之 auto_ptr
1.智能指针背后的设计思想 我们先来看一个简单的例子: void remodel(std::string & str) { std::string * ps = new std::string ...
- 智能指针分析及auto_ptr源码
简介 C++没有内存自动回收机制,对堆内存的管理就是简单的new和delete,每次new出来的内存都需要手动delete释放.但由于忘记.流程复杂或者异常退出等,都有可能导致没有执行delete释放 ...
- 【C++】智能指针简述(二):auto_ptr
首先,我要声明auto_ptr是一个坑!auto_ptr是一个坑!auto_ptr是一个坑!重要的事情说三遍!!! 通过上文,我们知道智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析 ...
- C++ 智能指针(shared_ptr/weak_ptr)原理分析
其主要的类关系如下所示(省略相关的类模板参数): 图1 从上面的类图可以清楚的看出shared_ptr内部含有一个指向被管理对象(managed object)T的指针以及一个__shared_cou ...
- 智能指针--C++
智能指针(一):STL auto_ptr实现原理 智能指针实际上是一个类(class),里面封装了一个指针.它的用处是啥呢? 指针与内存 说到指针自然涉及到内存.我们如果是在堆栈(stack)中分配了 ...
- c++ auto_ptr智能指针
c++ auto_ptr智能指针 该类型在头文件memory中,在程序的开通通过 #include<memory> 导入,接下来讲解该智能指针的作用和使用. 使用方法: auto_ptr& ...
- 【STL学习】智能指针之shared_ptr
前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择 几乎所有的程序都需要某种形式的引用计数智能指 ...
- C++智能指针简单剖析
导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题 ...
- 【转】C++智能指针简单剖析
原文链接:http://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看 <C++ Primer Plus>第六版,这的确是本好书 ...
随机推荐
- ERP_Oracle Fusion Application新一代ERP介绍
2014-12-31 Created By BaoXinjian
- Markdown 编辑模板
Hello,我是s1124yy. 名字的由来呢,是因为我QQ前4位是1124,但有的账号不能数字开头,所以就随手打了几个字母,最后就这么叫了.其实我很菜,但是我会努力的~~ 由于看到qsc的博客,所以 ...
- Calculations are rather interesting
Calculations are rather interesting, especially when some thoughts are involved therein.
- 通过Application传递数据代码
使用Application传递数据步骤如下:创建新class,取名MyApp,继承android.app.Application父类,并在MyApp中定义需要保存的属性 在整个Android程 ...
- Hadoop中两表JOIN的处理方法(转)
1. 概述 在传统数据库(如:MYSQL)中,JOIN操作是非常常见且非常耗时的.而在HADOOP中进行JOIN操作,同样常见且耗时,由于Hadoop的独特设计思想,当进行JOIN操作时,有一些特殊的 ...
- 解决Xshell和vim中文乱码(转载)
From:http://blog.csdn.net/lovey599/article/details/7275403 一般而言,乱码多是由于编码问题引起 的,在windows系统中,大多数情况下中文编 ...
- LNMP环境搭建配置memcache
原始出处 http://iceeggplant.blog.51cto.com/1446843/819576 memcached是高性能的,分布式的内存对象缓存系统,在动态应用中减少数据库负载,提升访 ...
- JS正则实例
<html> <body> </body> </html> <script> var strSrc = "xxa1b01c001y ...
- 修改Jenkins启动衍生进程的生命周期
Jenkins+jmeter 多线程测试java接口时爆错,导致无法生成html报告. 先介绍下场景: 在Jenkins中新建了一个Job,假设你在一些列Build Step之前/之后,启动了一个进程 ...
- oracle常用的数据迁移方法
源地址:http://wenku.baidu.com/link?url=lI6UYpvDs_y8ku6DytEZLl4GSJjQ0GAGPvv8txrbRoQKgqzTCMAfBZI5mn9t-KQk ...