C++ 智能指针

1 为什么要引入智能指针

  1. 如果一块内存被多个指针引用,但其中的一个指针释放且其余的指针并不知道,这样的情况会发生 挂起引用.
  2. 内存泄露. 在理想情况下,内存申请了又记得释放就可以了.但是往往在申请与释放之间程序可能出问题(异常,中途return,忘记释放),导致内存没有释放.

2 什么是智能指针

  1. 智能指针是存储指向动态分配(堆)对象指针的类. 用于实现自动正确的销毁动态分配的对象.防止内存泄漏. (自动调用类的析构函数来进行内存的释放)
  2. 智能指针比较通过的实现方法就是 引用计数 . 就将一个 计数器类指向的对象 相关联. 引用计数会跟踪这个类有多少个对象共享同一个指针.
    1. 每次 创建类的新对象 时,初始化指针,并将引用计数置为1;
    2. 当对象作为另一个对象的副本而创建时, 拷贝构造函数 拷贝指针并增加与之对应的引用计数;
    3. 对一个对象进行赋值时,赋值操作符减少左侧所指向对象的引用计数(如果计数器减少至0,则析构对象).同时呢**,增加右侧**所指对象的引用计数;
    4. 调用析构函数时,减少引用计数,若为0,则删除对象.

3 常用的指针指针

有4种智能指针: auto_ptr unique_ptr shared_ptr weak_ptr

auto_ptr

  • auto_ptr 实现的是资源的独占 就是说 一个对象智能由一个auto_ptr拥有
  • 赋值 的时候,会转移这个关系.
    • 就是在拷贝构造函数的时候需要记性转移
// 关键的拷贝函数,实现独占
    template<class U>
    AutoPtr& operator=(AutoPtr<U> &ptr) {
        if (ptr->m_ptr != this->m_ptr) { // 判断是否是自拷贝.若不是就要将右侧的指针转移到左侧
            delete this->m_ptr;
            this->m_ptr = ptr->m_ptr;
            ptr->release();
        }
        return *this;
    }

unique_ptr

  • 一个unique_ptr拥有它指向的对象. 某个时刻只能有一个unique_ptr指向一个给定对象
  • unique_ptr必须采用直接初始化
  • unique_ptr 不支持拷贝构造函数和赋值操作符重载.
    • 实现方法:将 拷贝构造函数 和 赋值操作符重载函数 私有化 .

shared_ptr

  • shared_ptr 即使用的引用计数的方法
  • 最安全的分配和使用动态内存方法: 调用** make_shared **
  • 必须采用直接初始化.
  • shared_ptr的 循环引用 可能会造成 内存泄漏
    • 指针间构成了一个死锁,这两块内存直到程序结束前都不会被释放
      在这里插入图片描述
      在这里插入图片描述

wake_ptr

  • 弱指针的一个重要使用场景就是为了 解决共享指针循环引用造成的内存泄漏
  • 它并不控制内存的生成期. 而是通过查询,查看指针的内存是否被释放了.只有不被释放的情况下才可以使用.
  • 它只引用,不计数. 指向一个 shared_ptr 管理的对象.
  • 使用之前需要检查weak_ptr是否为空指针. 有两个好处:
    • 对象被析构了 weak_ptr自动等于NULL
    • weak_ptr不会让引用计数错乱

实现auto_ptr

// 实现自动指针
template <class T>
class AutoPtr {
public:
	// 构造函数
	explicit AutoPtr(T* p = NULL) :m_ptr(p) {	// NOP	}
	// 拷贝构造函数
	template<class U> AutoPtr(AutoPtr<U> &rhs) 
		:m_ptr(rhs.release()){		// NOP	}
	// 析构函数
	~AutoPtr() {		delete this->m_ptr;	}
	/// 基本操作: get,release,重置
	T* get() const{	return m_ptr;	}

	T* release() {
		T* tmp = this->m_ptr; // 保存原来指针指向
		this->m_ptr = NULL;  // 将指针置为空
		return tmp; // 内存释放由析构函数完成
	}
	void reset(T* p) {
		if (m_ptr != p) {
			delete m_ptr;
			this->m_ptr = p;
		}
	}
	// 重载操作符
	T& operator*() const {
		if (m_ptr != NULL) {
			return *m_ptr;
		}
	}
	///指针指向
	T* operator->() {
		return m_ptr;
	}
	// 关键的拷贝函数,实现独占
	template<class U>
	AutoPtr& operator=(AutoPtr<U> &ptr) {
		if (ptr->m_ptr != this->m_ptr) {
			delete this->m_ptr;
			this->m_ptr = ptr->m_ptr;
			ptr->release();
		}
		return *this;
	}
private:
	T* m_ptr;
};

实现 unique_ptr

// 手写unique_ptr
template<class T>
class UniquePtr {
public:
	// 构造函数
	UniquePtr(T* ptr=NULL) :m_ptr(ptr){
	}
	T* operator*() {
		return *m_ptr;
	}
	T* operator->() {
		return m_ptr;
	}
	T* release() {
		if (m_ptr != NULL) {
			T* tmp = m_ptr;
			m_ptr = NULL;
			return tmp;
		}
		return NULL;
	}
	~UniquePtr() {
		if (m_ptr) {
			delete m_ptr;
			m_ptr = NULL;
		}
	}
private:
	UniquePtr(UniquePtr<T> &rhs) {
		//禁止拷贝构造函数
	}
	UniquePtr<T>& operator=(UniquePtr<T> &rhs) {
		// 禁止赋值
	}
	T *m_ptr;
};

实现 shared_ptr

// 手写shared_ptr
template<class T>
class SharedPtr {
public:
	// 构造函数
	SharedPtr(T* ptr = NULL) :m_ptr(ptr), m_count(NULL) {
		if (NULL != m_ptr) { // 不为空,则需要初始化计数器为1
			m_count = new int(1);
		}
	}

	// 拷贝构造函数
	SharedPtr(const SharedPtr<T>& rhs) :m_ptr(rhs.m_ptr),m_count(rhs.m_count){
		if (NULL != m_count) {
			++(*m_count); //自增1
		}
	}
	
	// 重载赋值运算符
	SharedPtr& operator = (SharedPtr& rhs) {
		*(rhs->m_count)++;
		this->~SharedPtr();
		this->m_ptr = rhs->m_ptr;
		this->m_count = rhs->m_count;
		return *this;
	}

	T operator*() {
		return *m_ptr;
	}

	T* operator->() {
		return m_ptr;
	}

	T* get_ptr() {
		renturn m_ptr;
	}

	~SharedPtr() {
		if (NULL != m_count && 0 == --(*m_count)) {
			delete m_ptr;
			m_ptr = NULL;
			delete m_count;
			m_count = NULL;
		}
	}
private:
	T* m_ptr; // 内置指针
	int* m_count; // 计数器
};

实现weak_ptr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值