【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:
相关推荐
lengxuenong11 小时前
枚举例题分析
c++·算法·青少年编程
“AI国潮设计-小江”12 小时前
【SDXL实战】用AI生成“财神爷蛋糕×英歌舞人物”潮汕国潮甜品IP,附Prompt与批量生成思路
开发语言·人工智能·python·aigc
繁华的地方不一定留下你的脚印12 小时前
C++线程如何安全停止与唤醒:std::jthread、stop_token与condition_variable
开发语言·c++
caoerzhong12 小时前
跨境海外仓怎么管:JeeWMS 开源 Java 仓库管理系统打通头程、海外仓与尾程
java·开发语言·开源
码云数智-大飞12 小时前
新手写 Python 代码,如何规范命名、减少 Bug
开发语言·python·php
福兮说12 小时前
JS 正则的六个坑:带 g 的 test() 一真一假、空匹配死循环、replace 里的 $
开发语言·前端·javascript·正则表达式
码艺-Alimjan12 小时前
Web 网站打包桌面应用的另一种方式,超级简单(C# exe 33Kb)
开发语言·前端·c#
沫璃染墨12 小时前
《从零入门Linux系统篇(五十一):线程篇·四——pthread线程库详解:从线程创建到终止与分离》
linux·运维·服务器·开发语言·c++·系统架构·线程
shada12 小时前
CMake指定 MSVC 工具集与 Windows SDK
c++·windows
垆边人似月.12 小时前
华为机考题:矩阵中的最长递增路径
c语言·c++