浅谈智能指针

一、概述

1.智能指针的分类

1.auto_ptr
2.unique_ptr
3.shared_ptr

2.智能指针的作用

若使用智能指针来管理堆内存的空间,那么在包含堆内存分配语句的代码块结束时,会自动调用智能指针的析构函数来对分配的内存进行释放,大大提高了代码的安全性,降低了编码复杂度。

二、智能指针创建对象

1.语法

1.auto_ptr<type> ap(new type(value));
2.unique_ptr<type> ap(new type(value));
3.shared_ptr<type> ap(new type(value));

2.为什么能如此创建对象

我们从源代码来剖析:

template<class T>
class auto_ptr{
   
private: 
    T*ap;
public:
  explicit auto_ptr(T* ptr=0) :ap(ptr){
   }
    ………………
	
}
auto_ptr<type> ap(new type(value));

​ 这里面的 new type(value)返回了一个临时对象的地址,然后调用auto_ptr将返回的地址保存进auto模板类对应的type类型的指针之中。

说明explicit

​ auto_ptr 的构造函数前面使用了explicit ,这就告诉编译器,我不接受隐式类型转换,也就是,我们不能将一个常规指针通过隐式类型转换变为auto_ptr类型的智能指针。

​ 一个常规指针想要作为智能指针的构造函数的参数,就需要如下示例的方法:

auto_ptr<double> ap;
double *p=new double;
ap=p;   //这是不被允许的,因为auto_ptr的构造函数声明为了explicit,不可以进行隐式的类型转换
//如果有不明白这种赋值操作为什么和构造函数有关的话,可以再去回顾一下构造函数的知识。
ap=auto_ptr<double>(p);  //这是允许的,允许显示的类型转换

三、智能指针内存管理原理

1.源码分析

template<class T>
class auto_ptr{
   
private: 
    T*ap;
public:
  	………………
  ~auto_ptr()throw()
  {
   
      delete ap;
  }
    ………………
	
}

在auto_ptr对象消解时,会调用他的析构函数,就将该对象中的指针ap指向的内存销毁掉了。

但是将一个常规指针转换为智能指针依旧是不安全的,即使是使用了显式类型转换,因为两个指针仍然会指向同一块内存。

四、智能指针的特性

先看一段代码:

auto_ptr<string> ps (new string("i"));
auto_ptr<string> vocation;
vocation=ps;

这种情况在某些时候是安全的,但是某些时候是不安全的,我们稍后会提到

1.所有权概念(auto_ptr和unique_ptr)

​ 对于特定的对象,只有一个智能指针可以拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象,然后,让赋值操作转移所有权。这样做就防止了两个指针指向同一块内存然后重复释放空间的问题。auto_ptr和unique_ptr都是如此,但是unique_ptr更加严格。

​ 接下来我们会在智能指针的区别讨论这一点。

2.创建智能更高的指针(shared_ptr)

​ 创建智能更高的指针,跟踪引用特定对象的智能指针数。称为引用计数。例如,赋值时,计数加一,指针过期时,计数减一。当最后一个指针过期时,也就是计数为0时,调用delete。

五、auto_ptr和unique_ptr的区别

前面我们提到了,他们两个都有所有权概念的特性,那么这两种指针的区别在哪里呢?

unique_ptr相比于前者更加的安全,因为它将以下代码视为非法,编译阶段就会报错

unique_ptr<string> p1(new string("ll"));
unique_ptr<string> p2;
p2=p1;

1.视为非法的原因

p1在给p2赋值后,会置空,或者说不再指向有效数据。此时如果

cout<<*p1<<endl;

执行这样的指令,会出现严重的运行时错误。但是由于unique_str编译时就会出错,那么就很好的避免了这个问题。

2.特殊情况下允许这种赋值

unique_ptr<string> demo(const char*s){
   
	unique_str<string> temp(new string(s));
	return temp;
}
unique_ptr<string> ps;
ps=demo("special");

允许这种赋值的原因:

​ 因为临时的unique_ptr对象会很快被销毁,没有机会用它来访问无效的数据。

而auto_ptr会允许unique_ptr视为非法的赋值,这是不安全的,所以,我们一般可以把auto_ptr舍弃。

六、unique_ptr的特殊地方

unique_ptr可以释放数组空间,其他两种指针都不可以。

七、解析所有权转移的原理

1.源代码分析

  auto_ptr& operator=(auto_ptr&rhs)throw()
    {
   
        reset(rhs.release());
        return*this;
    }

release()函数,是将智能指针所持有的指针释放,然后返回所有权

reset()函数的参数是智能指针要指向的新的对象,如果里面的参数指针指向的对象不是空的,那么将删除原来管理的对象。

最后返回新的auto_ptr的对象。

接下来调用拷贝构造函数,将新的对象拷贝给auto_ptr的对象

  auto_ptr(auto_ptr& rhs)throw():ap(rhs.release())
    {
   
    }

————————————————————

The End~~~~