对于一个初学者,常常会被野指针(垂悬指针)的问题所困扰。这就用到了我们今天讨论的智能指针来解决问题。

  野指针,也就是指向不可用内存区域的指针。通常对这种指针进行操作的话,将会使程序发生不可预知的错误。 
    
“野指针”不是NULL指针,是指向“垃圾”内存的指针人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用,野指针一般不会为NULL。野指针的成因主要有两种: 

  (一)指针变量定义时没有被初始化

         char* p;

         strcpy(p, “world”);//出错,没有初始化

  (二)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针

         char* p=(char*)malloc(4*sizeof(char));

         free(p);

         if(p!=NULL)//不能防止p不为空

           {strcpy(p, “world”);}//非法的拷贝,出错

    所以,在定义一个指针的时候最好就初始化,在释放指针内存时把指针置空。如果你觉得你都想不起来的话,那么掌握智能指针是必须掌握的。

   智能指针是用一个类来实现的,有类似指针的功能

   智能指针大概分为三种:

       (一)AutoPtr。这种智能指针是最早使用的一类智能指针,它的实现方式就是转移管理权。它有两种历史版本

  1. template<class T>
    class AutoPtr
    {
       private:
          T* _ptr;
          bool _owner;
          }
  2. template<class T>
    class AutoPtr
    {
       private:
          T* _ptr;
     }

  

wKioL1cPBUjis4pdAAAWWP7UzOg810.png

  第二个版本显然比第一个版本好,也是库后来采用的版本。如果用第一个版本的对象s1拷贝构造s2。

AutoPtr<T> s2(s1);出了作用域后析构函数将释放s2,但是s1仍然指向那块空间,使用s1将发生错误。

  (二)ScopedPtr。这种方法更为直接,竟然拷贝构造和赋值重载都会发生错误,那么我就不让你使用这两个函数,直接放入protected或者private中,这样在类外就无法调用这两个函数,也不用定义这两个函数,只用声明即可。

template<class T>
class ScopedPtr
{
public:

protected:
	ScopedPtr(const ScopedPtr<T>& sp);
	ScopedPtr<T> operator=(const ScopedPtr<T>& sp);

protected:
	T* _ptr;
};

      防卫智能指针在指针之间不进行拷贝和赋值时是非常有用的,效率高。

    (三)SharedPtr。带引用计数的智能指针,这种智能指针是用途最广泛的智能指针。

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		,_pCount(new long(1))
	{}
		
	SharedPtr(const SharedPtr<T>& sp)
		:_ptr(sp._ptr)
		,_pCount(sp._pCount)
	{
		++(*_pCount);
	}
	SharedPtr<T>& operator=(const SharedPtr<T>& sp)
	{
		if (this != &sp)
		{		
			_pCount = sp._pCount;
			_ptr = sp._ptr;
			++(*_pCount);
		}

		return *this;
	}
	~SharedPtr()
	{
		if (--(*_pCount) == 0)//当引用计数为1时释放空间
		{
			//delete _ptr;
			_del(_ptr);
			delete _pCount;
		}
	}
protected:
	T* _ptr;
	long* _pCount;
};

    

wKiom1cPC0fDVUoaAAAsfsK3NLI085.png


      每个智能指针对象里都有一个引用计数,并不是所有的智能指针对象共用一个引用计数,也不是每个对象都用自己的一个引用计数,对于指向同一块内存空间的智能指针共用一个引用计数。 这就解决了两个指针指向一块空间,当析构一个指针时,另一个指针出问题的情况。每当引用计数为1时才释放指向的那块空间,不然就引用计数减1.                   (四)WeakPtr。WeakPtr是辅助SharedPtr使用的智能指针,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。