智能指针!

简介: 智能指针!

智能指针

干什么用的?

将智能指针封装成类,利用类对象释放时调用析构函数的特点,将资源交给智能指针管理

利用对象生命周期控制资源——RAII

如何过渡到下面这个问题的?

智能指针的拷贝,默认是浅拷贝,即多个智能指针会指向同一份资源。这是没有问题的,符合智能指针的定义

这样做的问题是,同份资源会被多次析构

为了解决智能指针拷贝(拷贝构造、赋值拷贝)导致的多次析构的问题,衍生出了如下3种智能指针

auto_ptr  1

任何时候只允许一个智能指针对象对一份资源做管理

模拟实现auto_ptr

  template<class T>
  class auto_ptr {
  public:
    //构造
    auto_ptr(T* ptr=nullptr):_ptr(ptr){}
    //拷贝构造
    auto_ptr(auto_ptr<T>& ap)
    {
      _ptr = ap._ptr;
      ap._ptr = nullptr;
    }
    //赋值拷贝 需要考虑特殊情况
    auto_ptr& operator=(auto_ptr& ap)
    {
      delete _ptr;
      _ptr = ap._ptr;
      ap._ptr = nullptr;
      return *this;
    }
    //析构函数
    ~auto_ptr()
    {
      if (_ptr != nullptr)
      {
        delete _ptr;
        _ptr = nullptr;
      }
 
    }
    //->
    T* operator->()
    {
      return _ptr;
    }
    //*
    T& operator* ()
    {
      return *_ptr;
    }
  private:
    T* _ptr;
  };
}

int* a =nullptr;

delete a 为什么不会报错

因为 C++ 标准规定对空指针进行删除操作时,会忽略这个操作,不会引发运行时错误。

int b=0;

int *a =&b

delete a 为什么会报错

因为delete是用于释放new出来的堆空间(动态分配出来的空间),而a指向的空间属于栈上的空间

比较拷贝构造与赋值拷贝之间的差异

为什么要delete _ptr?

因为一个auto_ptr对象只能管理一个资源,所以要先释放自身管理的资源

为什么要这样做?

因为一个资源只能被一个auto_ptr对象管理。

为什么不delete ap._ptr,因为该auto_ptr还有可能被赋值

特殊情况考虑

2个auto_ptr对象的_ptr都为nullptr(表明这两个对象没有管理任何资源)

就会出现delete nullptr的情况,所以要在构造函数部分加判空判断

int* a =nullptr;

delete a 为什么不会报错

因为 C++ 标准规定对空指针进行删除操作时,会忽略这个操作,不会引发运行时错误。

int b=0;

int *a =&b

delete a 为什么会报错

因为delete是用于释放new出来的堆空间(动态分配出来的空间),而a指向的空间属于栈上的空间

为什么拷贝构造没有delete _ptr

因为管理资源的对象还没有被创建出来,也就是说该对象还没有管理任何资源

总结:拷贝构造与赋值拷贝

相同点就是:它们都要保证一个资源只能被一个对象管理

不同点就是:拷贝构造是一个已存在的对象拷贝给一个尚未存在的对象,所以不用释放

                     赋值拷贝是两个已存在的对象间的拷贝,所以要释放

unique_ptr 0

防拷贝,也就是说该智能指针禁止拷贝

具体就是将拷贝构造与赋值构造这两个函数禁用

template <class T>
  class unique_ptr {
  public:
    //默认构造 表示没有管理任何资源
    unique_ptr(T* ptr = nullptr) :_ptr(ptr) {}
    //析构函数
    ~unique_ptr()
    {
      if (_ptr != nullptr)
      {
        delete _ptr;
        _ptr = nullptr;
      }
 
    }
    //->
    T* operator->()
    {
      return _ptr;
    }
    //*
    T& operator* ()
    {
      return *_ptr;
    }
    unique_ptr(unique_ptr<T>& up) = delete;
    unique_ptr& operator=(unique_ptr<T>& up) = delete;
  private:
    T* _ptr;
  };

shared_ptr  >1

允许拷贝,利用计数器管理使用同一份资源的智能指针,当计数器等于0时才释放智能指针管理的资源

这意味着什么?

这意味着可以有多个shared_ptr对象管理同一份资源

  template<class T>
  class shared_ptr {
  public:
    //构造
    shared_ptr(T* ptr=nullptr):_ptr(ptr),_pcount(new int(1)){}
    //拷贝构造
    shared_ptr(shared_ptr& sp)
    {
      _ptr = sp._ptr;
      _pcount = sp._pcount;
      *_pcount++;
    }
    //赋值构造
    shared_ptr& operator=(shared_ptr& sp)
    {
      if (sp._ptr != _ptr)
      {
        if (-- ( * _pcount) == 0)
        {
          delete _ptr;
          delete _pcount;
        }
        _ptr = sp._ptr;
        _pcount = sp._pcount;
        (* _pcount)++;
      }
      return *this;
    }
    //析构
    ~shared_ptr()
    {
      if (--(*_pcount) == 0)
      {
        if (_ptr != nullptr)//特殊情况,_ptr有可能指向空,就对他做处理
        {
          delete _ptr;
          _ptr = nullptr;
        }
        delete _pcount;
        _pcount = nullptr;
      }
    }
    //->
    T* operator->()
    {
      return _ptr;
    }
    //*
    T& operator* ()
    {
      return *_ptr;
    }
    //引用计数
    int use_count()
    {
      return *(_pcount);
    }
  private:
    T* _ptr;
    int* _pcount;
  };
}

循环引用问题

shared_ptr存在循环引用问题,如下例

将ListNode交给shared_ptr管理

运行结果  没有如预期结果释放资源

原因:

程序运行时

程序 结束后

为什么shared_ptr<ListNode>_next 与shared_ptr<ListNode>_prev不在程序结束的时候释放呢?因为它们是new出来的,需要手动释放

weak_ptr

解决循环引用

上述问题的关键其实就是多了一个shared_ptr,导致程序结束时计数器不为0

weak_ptr 接受一个shared_ptr对象 但是计数器不+1

实现:

  template<class T>
  class weak_ptr {
  public:
    //构造
    weak_ptr(T* ptr=nullptr):_ptr(ptr){}
    //拷贝构造
    weak_ptr(shared_ptr<T>& sp)
    {
      if(sp.use_count!=0)
      _ptr = sp.get();
    }
    //赋值拷贝
    weak_ptr& operator=(shared_ptr<T>& sp)
    {
      if (sp.use_count() != 0)
      {
        _ptr = sp.get();
      }
      return *this;
    }
    //析构
    ~weak_ptr()
    {
      _ptr = nullptr;
    }
    //->
    T* operator->()
    {
      return _ptr;
    }
    //*
    T& operator* ()
    {
      return *_ptr;
    }
  private:
    T* _ptr;
  };
}


相关文章
|
6月前
|
C++
智能指针的讲解
智能指针的讲解
70 2
|
6月前
|
安全 C++
深入理解C++11智能指针
深入理解C++11智能指针
72 1
|
5月前
|
编译器 Linux C++
C++智能指针
**C++智能指针是RAII技术的体现,用于自动管理动态内存,防止内存泄漏。主要有三种类型:已废弃的std::auto_ptr、不可复制的std::unique_ptr和可共享的std::shared_ptr。std::unique_ptr通过禁止拷贝和赋值确保唯一所有权,而std::shared_ptr使用引用计数来协调多个指针对同一资源的共享。在C++17中,std::auto_ptr因设计缺陷被移除。**
|
6月前
|
存储 安全 程序员
C++:智能指针
C++:智能指针
52 5
为什么需要智能指针?
为什么需要智能指针?
43 0
|
6月前
|
编译器 C++
C++之智能指针
C++之智能指针
27 0
|
11月前
|
存储 C++
C++智能指针详解
C++智能指针详解
47 0
|
存储 编译器
C++11智能指针(一)
C++11智能指针
56 0
|
程序员 C++ 开发者
深入C++常用的三个智能指针
C++是一门强大的编程语言,但是在内存管理方面却存在着一些问题。手动管理内存不仅费时费力,而且容易出错。因此,C++中引入了智能指针这一概念,以更好地管理内存。