使用TR1的智能指针
作为C++程序员,在没有智能指针,手动管理内存的蛮荒岁月里,可以说是暗无天日,痛苦异常。直到上帝说,还是要有光,于是智能指针进了标准。C++码农的日子总算好起来了。
虽然一直鄙视着没有显式指针的语言,但是对其自动垃圾回收机制还是翘首以盼的,TR1的智能指针总算可以拿来慰藉下了。
要使用VS2008 SP1的智能指针,我们需要加入头文件 memory.h(linux 下是 tr1\memory.h),
智能指针主要是 auto_ptr, shared_ptr, weak_ptr, unique_ptr ;其中模板auto_ptr是C++98提供的解决方案,C+11已将其摒弃。然而,虽然auto_ptr被摒弃,但它已使用了好多年.因为auto_ptr潜在的内存奔溃问题,所以不推荐使用它,本文也不准备讨论该指针.另外unique_ptr在Tr1中还未引入.
Show me The Code
namespace tr1SharedPoint
{
class Ap
{
public:
	Ap(){
		std::cout << "Ap Construct"<<std::endl;
	};
	~Ap(){
		std::cout << "Ap Destruct"<<std::endl;
	};
	void pointerOutput(){
		std::cout << "Use smart pointer to use me "<<std::endl;
	}
};
typedef std::tr1::shared_ptr<Ap> spAp;
}
测试代码
tr1SharedPoint::Ap *ap = new tr1SharedPoint::Ap;
ap->pointerOutput();
执行结果:
Ap Construct
Use smart pointer to use me
可见,这里没有调用析构函数,内存泄漏就此发生了,需要在测试代码中 加入 delete ap补救之,也就是我们以前经常做的事情。
- shared_ptr基本使用
 
修改测试代码:
tr1SharedPoint::spAp ap(new tr1SharedPoint::Ap);
ap->pointerOutput();
执行结果:
Ap Construct
Use smart pointer to use me
Ap Destruct
如此,一个指针的完美闭环就此产生了。我们不需要再手动添加delete语句,等到share_prt的作用域消失时,将自动调用Ap类的析构函数。很多局部锁的类也是如此构造的;
- weak_ptr基本使用
上面的代码 无法使用weak_ptr直接替换shared_ptr,因为weak_ptr是一种不控制指向对象生存期的智能指针,它指向一个shared_ptr管理的对象.调用lock()将返回一个shared_ptr对象,通过判断该值可以知道weak_ptr指向的内存是否已经被释放. 
typedef  std::tr1::weak_ptr<Ap> wpAp;
tr1SharedPoint::wpAp wp = ap;//一个weak_ptr可以直接由一个shared_ptr赋值
测试代码如下:
tr1SharedPoint::wpAp wp;
{
	tr1SharedPoint::spAp ap(new tr1SharedPoint::Ap);
	wp = ap;
	if(wp.lock()){
		std::cout << "ap not Destruct" <<std::endl;
		std::cout <<"refence Num " <<wp.use_count() <<std::endl;
	}
	ap->pointerOutput();
}
	if(!wp.lock()){
		std::cout << "ap IS Destruct" <<std::endl;
		std::cout <<"refence Num " <<wp.use_count() <<std::endl;
	}
运行结果
Ap Construct
ap not Destruct
refence Num 1
Use smart pointer to use me
Ap Destruct
ap IS Destruct
refence Num 0
以上可知,weak_ptr能通过lock()判断其管理的shared_ptr是否释放,通过use_count()知道shared_ptr被引用的次数
可是 只了解这么一点知识就可以了么?
答案是,可能是的。如果你只是个总忘记调用delete的C++程序员。有兴趣的可以继续阅读.
知道更多
按上面的智能指针的用法,我们使用了new运算符,却没有显式的delete,造成了代码的不对称感,为了消除这种不对称,而又使用智能指针,我们最合适的方案是使用make_shared函数来声明内存的分配,可惜的是,TR1中并没有包含这个函数,限于本文的标准范围,我们只能通过boost等三方库来支持,可是如果使用了boost的内存语法,又没有必要使用TR1了.一个可能的方案就是把new给封装起来,眼不见为静.后期介绍C++11后,我们再来研究现在C++是如何完整的处理动态内存问题的.其实,这个问题在C++ Primer中有很详细的介绍.
坚持只使用智能指针,就可以避免 1.忘记delete内存 2.使用已经释放掉的对象 3.同一块内存释放两次 这3类问题,对于一块内存,只有在没有任何智能指针指向它的情况下,智能指针才会自动释放它.
- 在可能循环引用的类中,使用weak_ptr
weak_ptr更常用的用法是解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。 
class A;
class B;
typedef std::tr1::shared_ptr<A> APtr;
typedef std::tr1::shared_ptr<B> BPtr;
typedef std::tr1::weak_ptr<A> AWeakPtr;
typedef std::tr1::weak_ptr<B> BWeakPtr;
class A {
public:
  BWeakPtr b; // 注意这里
  ~A () {
    printf ("A released\n");
  }
};
class B {
public:
  AWeakPtr a; // 注意这里
  ~B () {
    printf ("B released\n");
  }
  void output () {
    printf ("I'm B\n");
  }
};
int main () {
  APtr a(new A());
  BPtr b(new B());
  a->b = b;
  b->a = a;
  BPtr b2(a->b.lock());
  b2->output();
  return 0;
}
运行结果
I'm B
B released
A released
可见,这里的A和B都能被正确释放了;
- 使用 
std::tr1::enable_shared_from_this作为基类。比如: 
class A : public std::tr1::enable_shared_from_this<A>
{
public:
    std::tr1::shared_ptr<A> getSharedPtr() {
    return shared_from_this();
  }
};
当使用了 shared_ptr 的时候,我们可能需要在所有的地方都使用它,否则就不容易达到管理生存期的目的了。但有的时候,我们手头上只有对象的原始指针,比如在对象的函数内部,我们只有 this。这就迫切的需要一个功能:如何从对象的裸指针中,生成我们需要的 shared_ptr。
有人可能会觉得这个简单,shared_ptr a(this); 不就行了么?很遗憾的告诉你,这样不行,会出问题。为什么呢?因为这里的 a,手中对 this 的引用计数只有 1,它无法知道其他地方智能指针对 this 这个指针(就是这个对象)的引用情况,因此当 a 的生命周期结束(比如函数返回)的时候,this 就会被它毫不留情的释放掉,其他地方的相关智能指针,手中拿着的该对象指针已经变成非法。因此,我们需要使用std::tr1::enable_shared_from_this 作为基类将类的this指针的引用导出来.
使用TR1的智能指针的更多相关文章
- 智能指针tr1::shared_ptr、boost::shared_ptr使用
		
对于tr1::shared_ptr在安装vs同一时候会自带安装,可是版本号较低的不存在.而boost作为tr1的实现品,包括 "Algorithms Broken Compiler Work ...
 - C++11能用智能指针
		
[C++11能用智能指针] shared_ptr 是一引用计数 (reference-counted) 指针,其行为与一般 C++ 指针即为相似.在 TR1 的实现中,缺少了一些一般指针所拥有的特色, ...
 - auto_ptr,shared_ptr 智能指针的使用
		
Q: 那个auto_ptr是什么东东啊?为什么没有auto_array?A: 哦,auto_ptr是一个很简单的资源封装类,是在<memory>头文件中定义的.它使用“资源分配即初始化”技 ...
 - Qt 智能指针学习(7种指针)
		
Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...
 - Qt 智能指针学习(7种QT的特有指针)
		
从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include <QApplication> #include <QLabel> int main(int arg ...
 - Qt 智能指针学习(7种QT智能指针和4种std智能指针)
		
从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include <QApplication> #include <QLabel> int main(int arg ...
 - Qt 智能指针学习
		
原地址:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include & ...
 - 智能指针 shared_ptr 解析
		
近期正在进行<Effective C++>的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦.写篇blog整理一下. LinJM @HQU s ...
 - [转]Qt 智能指针学习
		
从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ #include <QApplication> #include <QLabel> int main(int arg ...
 
随机推荐
- parted 分区
			
Linux下的GPT分区 GPT分区 这是另外一种分区,针对MBR分区,它有很多优点: (1)几乎突破了分区个数的限制. 在GPT分区表中最多可以支持128个主分区. (2)单个分区容量几乎没有限制. ...
 - pt-table-checksum校验mysql主从数据一致性
			
主从数据的一致性校验是个头疼的问题,偶尔被业务投诉主从数据不一致,或者几个从库之间的数据不一致,这会令人沮丧.通常我们仅有一种办法,热备主库,然后替换掉所有的从库.这不仅代价非常大,而且类似治标不治本 ...
 - 自定义ajax
			
// 动态添加script获取里面的数据,,可实现跨域,不跨的当然也可以 getFile:function(params){ try{ //创建script标签 var cbName=params.c ...
 - SPSS 分布类型的检验
			
假设检验的标准步骤: 1.建立假设:根据问题的需要提出原假设H0,以及其对立面备择假设H1. 2.确立检验水准:即设立小概率事件的界值α. 3.进行试验:得到用于统计分析的样本,以该试验的结果作为假设 ...
 - 【转】python操作mysql数据库
			
python操作mysql数据库 Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口. Python 数据库接口支持非常多的数据库 ...
 - c语言memset源码
			
c语言memset源码 一.用法 void *memset(void *s, int ch, size_t n);作用:将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的 ...
 - python 爬虫005-爬虫实例
			
实例一:扒取猫眼电影TOP100 的信息 #!/usr/bin/env python # -*- coding: utf-8 -*- """ 扒取猫眼电影TOP100 的 ...
 - UVA-1619 Feel Good (单调队列)
			
题目大意:给一个非负整数序列,求出一个使得区间和乘以区间最小值最大的区间. 题目分析:单调队列.维护两个数组,l[i]表示以a[i]为最小值的左半区间的最左边端点,r[i]表示以a[i]为最小值的右半 ...
 - su | sudo su | sudo -i
			
su <user> <user> <user> 需要输入user的密码,该命令改变user id,执行过后,以<user>中定义的用户运行shell,就 ...
 - JQuery对象与javascript对象的转换
			
jQuery 对象是通过 jQuery 包装DOM 对象后产生的对象. jQuery 对象是 jQuery 独有的,其可以使用 jQuery 里的方法,但是不能使用 DOM 的方法:例如: $(&qu ...