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;
}
运行结果: