C++模板技术和STL实战开发(5)——STL实用编程技术(5)——仿函数、Lambda表达式、智能指针

1.仿函数的原理剖析

什么是仿函数?

示例代码:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>

using namespace std;

int main()
{
	vector<int> myVec;
	sort(myVec.begin(),myVec.end(),greater<int>());
}

上述代码中greater<int>()就是仿函数,它是一个对象,调用了()重载的对象

一个类可以因为重载某一运算符而改变对象的外观

重载了运算符()的类产生的对象,称为仿函数(即函数对象)

原理剖析:

示例代码:

#include <iostream>

using namespace std;

class Add
{
public:
	Add(int x)
		:m_x(x)
	{

	}
	int operator()(int a, int b)
	{
		return a + b + m_x;
	}
private:
	int m_x;
};
int main()
{
	Add myAdd1(100);
	cout << myAdd1(1, 2) << endl;

	Add myAdd2(200);
	cout << myAdd2(1, 2) << endl;
}

上述对于仿函数myAdd(1,2)的调用绑定了对象,它会根据对象不同的值返回不同的值

调用仿函数,为什么不用函数指针?

因为当我们使用仿函数时,实际是在调用一个对象

我们可以为函数附加额外的信息,从而充分利用C++内存对象布局中的代码绑定能力,比如上述代码中为函数传入参数1和2,来确保不同的结果

STL=算法+数据结构,仿函数完成了算法与数据结构的组合能力(后面理解更深入了再多补充)

2.Lambda表达式原理剖析

Lambda表达式让我们便捷地创建临时函数,编译器为我们临时构建一个函数,用完就扔掉,是C++11提供一种语法机制,让我们灵活地生成语句块

当我们直接编写一个函数时,与它相关的cpp文件就有可能调用这个函数,而当我们不想把这样的函数暴露给其他用户调用时,甚至连private也不想写,不想让别人知道有这样的函数存在,我们就可以使用Lambda表达式定义这样的函数供自己的一段代码中调用,编译器会让它在它的作用域内消亡,这样避免了开发中,编码人员临时处理的语句块暴露的风险,提高了模块的内聚性

示例代码:

#include <iostream>
using namespace std;

int main()
{
	auto f=[](int x) {cout << x * 2 << endl; };
	f(10);
}

3.内存析构异常原理剖析

RAII:资源分配应该与对象生命周期绑定起来,创建对象的时候分配资源,销毁对象的时候回收资源

智能指针就是把裸指针封装成一个类,需要重载运算符*和->

示例代码:

#include<iostream>
using namespace std;
template <typename T>
class MyPtr
{
private:
	T* ptr;
public:
	MyPtr(T* p)
		:ptr(p)
	{
		cout << "构造时创建对象" << endl;
	}

	~MyPtr()
	{
		cout << "析构时回收对象" << endl;
		delete ptr;
        cout << "析构时已经回收对象" << endl;
	}

	T& operator*()
	{
		return *ptr;
	}

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

int main()
{
//在作用域中析构局部变量a造成异常
/*
	int a = 10;
	{
		MyPtr<int>p(&a);
		cout << *p << endl;
	}
*/
//在作用域中析构new出的变量
	int *pInt = new int(10);
	{
		MyPtr<int>p(pInt);
		cout << *p << endl;
	}
}

在作用域中析构局部变量a的运行结果:

a为局部变量,它定义在函数栈帧中,根本不需要delete,因为new和delete是针对堆的内存的

在作用域中析构pInt的运行结果:

pInt为new出来的,也就是在堆上,可以被delete来释放

4.SharePtr的引用计数原理的仿真实现

在程序中,常常多个指针指向同一资源,此时资源的释放不能仅仅取决于一个对象的生命周期

只要还有指针持有资源,那就一定不能释放

这也就是指针引用计数的由来,有指针在引用,那我们就让引用计数加1;有指针变量的生命周期结束,那么引用计数减1

SharePtr仿真实现代码:

#include<iostream>
using namespace std;
template <typename T>
class SharePtr;
//定义计数模板
template <typename T>
class Res_ptr
{
private:
	T* res_p;  //用以指向资源的裸指针
	int use_num;  //引用计数器

	Res_ptr(T* p)
		:res_p(p),use_num(1)
	{
		cout << "构造函数" << endl;
	}
	~Res_ptr()
	{
		delete res_p;
		cout << "Res_Ptr析构函数" << endl;
	}

	friend class SharePtr<T>;
};

template<typename T>
class SharePtr
{
public:
	SharePtr(T *p, T i)
		:ptr(new Res_ptr<T>(p)),val(i)
	{
		cout << "SharePtr的构造函数:" << "use_num = " << ptr->use_num << endl;
	}

	SharePtr(const SharePtr& orig)
		:ptr(orig.ptr), val(orig.val)
	{
		++ptr->use_num;
		cout << "SharePtr的构造函数:" << "use_num = " << ptr->use_num << endl;
	}

	~SharePtr()
	{
		cout << "SharePtr的析构函数:" << "use_num = " << ptr->use_num << endl;
		if (--ptr->use_num == 0)
		{
			delete ptr;
		}
	}

private:
	Res_ptr<T>* ptr;   //指向计数类
	T val;
};
int main()
{
	{
		SharePtr<int> hpA = SharePtr<int>(new int(42), 100);
		{
			SharePtr<int> hpB(hpA);
			SharePtr<int> hpC(hpB);
			SharePtr<int> hpD = hpA;
		}
		cout << "内层括号结束" << endl;
	}
	cout << "中层括号结束" << endl;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值