【C++11】包装器,智能指针

当面对下面场景时,发现count变量作为静态变量,但是有三个地址,并且count的计数都是1,无法做到每调用一个函数对象就使count++,用来统计调用函数的个数,因为每一组不同的模板参数,都会生成一份独立的函数实例。怎么简化调用接口,并且实现count公用同一块空间?

一.包装器

概念

  • function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。
  • 可以把不同的函数其实例化为一个类型,或者把可调用对象存储到容器中
  • function可以对仿函数,函数指针,lambda进行包装
  • 使用:function<return_val(parameter)>

情景1:

  • 使用包装器包装后,只实例化一份count
  • 另外发现f1和f2的类型都相同,只有在同一个类型下static变量才会定义一份,所以共用一个变量

情景2:

逆波兰表达式求值


std::bind使用

std::bind函数,像函数包装器,是一个函数模板,接收一个可调用对象,生成一个新的可调用对象来"适应"源对象的参数列表。可以实现函数传递参数顺序调整

  • 利用下面标定参数列表的位置:

场景1:

场景2:

情景3:

  • 类内静态成员函数,bind时不需要加this指针
  • 类内非静态成员函数 ,bind时第一个参数添加实例化对象的地址 (使用&),或者传入匿名对象
  • binder类重载了operator()

说明

  • function的和bind底层都是仿函数,bind重载了operator(),通过指针或者对象调用函数,绑定成员函数时,传对象的地址

智能指针

需要的理由

  • 于是在catch到异常时delete,没有catch时delete。可是这样繁杂,于是有了智能指针
  • throw;的作用 :重新抛出当前捕获的异常对象,继续抛给调用栈的上一层,这样保证没有吞掉异常,错误信息被上一层感知

概念

  • RAII是一种利用对象生命周期来控制程序资源的技术,在对象构造时获取资源 ,最后在对象析构时释放资源。于是我们不用显式释放资源,保证对象析构时候释放资源
  • 这是智能指针的核心原理

智能指针

auto_ptr
  • 管理权转移,拷贝时,会把被拷贝对象的资源管理权转移给拷贝对象
  • 导致被拷贝对象悬空,再次访问该对象时报错
  • 如果不把sp1置空,由于浅拷贝,sp2析构一个后sp1再析构就成了析构空指针
unique_ptr
  • 于auto_ptr的区别在于不能拷贝不能赋值重载
shared_ptr
  • 通过引用计数实现多个shared_ptr对象之间的共享资源
  • 当一个shared_ptr对象销毁时,引用计数--
  • 当引用计数减到0时,才释放资源
  • 支持拷贝构造

注意:引用计数不能使用静态变量 的方式,静态成员变量属于类本身而不是某个具体的对象,所有的类共享这一个静态变量 。当有不同类型的shared_ptr时,一个类型的引用计数--,会影响到另一个不相干的类型引用计数--。所以应该类内定义指针计数,当拷贝构造时将该指针传给this对象,再进行操作。


概念图:

shared_ptr的实现
cpp 复制代码
namespace Mshared_ptr
{
	template<class T>
	class Mshared_ptr
	{
	public:
		Mshared_ptr(T* ptr = nullptr) :_ptr(ptr), _pcount(new int(1)) {}
		
		Mshared_ptr<T>& operator=(Mshared_ptr<T>& ap)
		{
			if (_ptr == ap._ptr)
			{
				return this;
			}
			if (--(*_pcount) == 0)
			{
				delete _ptr; 
				delete _pcount;
			}
			_ptr = ap._ptr;
			_pcount = ap._pcount;
			_pcount++;
			return *this;
		}
		Mshared_ptr(const Mshared_ptr<T>& up):_ptr(up._ptr), _pcount(up._pcount)
		{
			*(_pcount)++;
		}

		T& operator*() { return *_ptr; }
		T* operator->() { return _ptr; }
		T* getPtr() const
		{
			return _ptr;
		}

		int Rcount() const
		{
			return *_pcount;
		}


		~Mshared_ptr() { 
			if (--(*_pcount) == 0)
			{
				cout << "delete ->" << _ptr << endl; 
				delete _ptr;
				delete _pcount;
			}
		}
	private:
		T* _ptr;
		int* _pcount;
	};
};
情景1:
相关推荐
sthnyph10 小时前
QT开发:事件循环与处理机制的概念和流程概括性总结
开发语言·qt
大尚来也10 小时前
Java 反射:从“动态魔法”到生产实战的避坑指南
开发语言
无心水10 小时前
Java时间处理封神篇:java.time全解析
java·开发语言·python·架构·localdate·java.time·java时间处理
yangtuoni11 小时前
vscode调试C++程序
c++·ide·vscode
m0_5879589511 小时前
C++中的命令模式变体
开发语言·c++·算法
~无忧花开~11 小时前
React生命周期全解析
开发语言·前端·javascript·react.js·前端框架·react
剑心诀11 小时前
02 数据结构(C) | 线性表——顺序表的基本操作
c语言·开发语言·数据结构
人间打气筒(Ada)11 小时前
如何基于 Go-kit 开发 Web 应用:从接口层到业务层再到数据层
开发语言·后端·golang
2501_9249526911 小时前
代码生成器优化策略
开发语言·c++·算法
清风徐来QCQ11 小时前
八股文(1)
java·开发语言