C++的智能指针学习笔记(初)

C++ primer plus 16.2节介绍了auto_ptr,该模板类在C++11中已弃用,目前已被shared_ptr代替。
auto_ptr又叫做智能指针,用于管理动态内存分配的用法。

为什么要有auto_ptr?

首先看一个例子,

void remodel(string &str){
  string *ps = new string(str);
  ...
  str = ps;
  return;
}

此例子有什么缺陷呢?
函数结束的时候没有释放内存,这导致了内存的泄露,指针ps会被释放,但是其指向的内存并没有被释放。一般来说,解决new导致的内存泄露的方法是在return之前使用delete.
但凡是涉及到“别忘了”的操作,都不是最佳的操作,因为一定会有开发者忘记,或者在不经意间删除或者注释掉了这些代码。
就算是没有忘记,也会因为一些别的操作导致内存无法释放,例如以下的代码:

void remodel(string &str)
{
  string *ps = new string(str);
  ...
  if(xxx){
    throw exception();
  }
  str = *ps;
  delete ps;
  return;
}

在delete执行之前,如果执行过程中产生了异常并抛出,则后续的指令都不会执行,这仍将导致内存泄露。

如何解决

首先,我们知道,C++创建一个对象有两种方式,new和直接声明。new一个对象将在堆中动态分配内存来创建一个对象,而直接声明将会在栈内存中创建对象。
(所谓的堆,是指程序内部除了栈和静态存储区之外的"自由空间(free store)",堆内存用于在程序运行时分配对象。)
前者的生命周期是全局的,后者则受到作用域限制,也就是说对于前者产生的对象,如果不去主动释放它,则该对象所占据的内存会一直存在,如果没有指针可以指向它,则会导致内存泄露。
而直接声明的对象,在一个类对象过期的时候,析构函数会在一个对象过期的时候自动执行从而将该对象释放。

不妨这样思考,如果指针能被封装为一个对象,则这个包含指针的对象过期的时候调用其析构函数,将该指针指向的对象delete,不就能够把它指向的内存也释放了吗?
于是auto_ptr便诞生了,auto_ptr是一个模板类,这样便可以创建指向任何类型的智能指针。

auto_ptr的设计和使用

template<class T>class auto_ptr{
  public:
  explicit auto_ptr(T* p = 0) throw();
};

throw()意味着构造函数不引发异常,因此请求T类型的auto_ptr将获得一个指向T类型的auto_ptr.

这样便定义好了一个智能指针,其实非常简单,就是在构造的时候将普通的指针放入了auto_ptr模板类中
使用的时候

auto_ptr<double> ap(new double);//在构造函数中填入new出来的对象
*ap = 23.3;//ap对象的地址其实就是new出来的double对象的地址,所以可以用指针取值的方式赋值。

所以,改造文章开头的remodel函数:

void remodel(string &str){
  auto_ptr<string> ps(new string(str));
  ...
  if(xxx) throw exception();

  str=*ps;
  return;
}

这里,便不再需要使用delete了。

shared_ptr和unique_ptr

C++11摒弃了auto_ptr,主要是由于auto_ptr无法进行指针的传递。auto_ptr必须显式地初始化,即auto_ptr<string> ps(new string("sdf")),
为了多个指针指向一个new出的对象,C++11提出了shared_ptr,
shared_ptr中增加了引用计数,有N个指向一个同一个内存区域的shared_ptr时,它们共同维护一个引用计数器。
shared_ptr的大概实现如下:

template<typename T> class shared_ptr{
  
private:
  T* _ptr;//指向的对象
  int *_count;//引用计数器

public:
  ...
  shared_ptr():_ptr((T*)0),_count(0){}
  ~shared_ptr(){
    if(_ptr && --*count==0){
      delete _ptr;
      delete _count;
    }
  }
};

当智能指针的析构函数启用时,只有引用计数为0的时候,才会进行析构。

原文地址:https://www.cnblogs.com/goto2091/p/13804187.html