【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:
相关推荐
十五年专注C++开发2 小时前
CMake进阶:SelectLibraryConfigurations模块
c++·cmake·自动化构建
量子炒饭大师2 小时前
【C++入门】Cyber深度漫游者的初始链路——【类与对象】初始化成员列表
开发语言·c++·dubbo·类与对象·初始化成员列表
独自破碎E2 小时前
BISHI43 讨厌鬼进货
android·java·开发语言
mmz12072 小时前
逆序对问题(c++)
c++·算法
化学在逃硬闯CS2 小时前
Leetcode110.平衡二叉树
数据结构·c++·算法·leetcode
谢铭轩2 小时前
题解:P8035 [COCI 2015/2016 #7] Otpor
c++·算法
纯.Pure_Jin(g)2 小时前
【Python练习四】Python 算法与进阶特性实战:数组、序列化与位运算专项练习(3道经典练习带你巩固基础——看完包会)
开发语言·vscode·python
阿猿收手吧!2 小时前
【C++】模块:告别头文件新时代
开发语言·c++
星火开发设计2 小时前
虚析构函数:解决子类对象的内存泄漏
java·开发语言·前端·c++·学习·算法·知识