1. 指针控制——nullptr
从0到NULL再到nullptr
最开始时,典型的初始化指针是将其指向一个空的位置,比如0。因为大多数计算机通常不允许程序员往地址为0的空间写入内容,一旦执行即程序退出。
因此一般会定义int* myptr_=0; int myptr_=NULL
一般情况下NULL
是个宏定义:
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL((void*) 0)
#endif
:::info 这会带来二义性,字面常量0的二义性:
- 整型
-
nullptr
C++11中,出于兼容性考虑,定义了nullptr,指针空值类型常量。
2. 默认函数的控制
C++中声明自定义的类,编译器会默认帮助程序员生成他们没有自定义的成员函数:
构造
- 拷贝构造
- 拷贝赋值(operator=)
- 移动构造
- 移动拷贝
- 析构
但是一旦程序员实现了这些函数的自定义版本,编译器不再为该类生成默认版本。
- C++11中,标准提供了新的机制来控制默认版本函数的生成。重用了default关键字,可以默认函数定义或是声明时加上=default来显示地指定使用默认版本。
-
3. lambda函数
语法定义:
[capture](parameters) mutable ->return-type{statement}
capture:捕获列表,[]是lambda的引出符,编译器根据该符号判断下面的代码是否是lambda函数。
- parameters:参数列表,可以省略如不需要。
- mutable:默认lambda是const函数
- ->return-type:返回类型
- statement:函数体
lambda函数可以通过捕获列表访问一些上下文中的数据,捕获列表描述了上下文中哪些数据可以被lambda函数使用,以及具体的使用方式(以值传递还是引用传递)
捕获列表有以下几种形式:
- [var] 值传递的方式捕捉变量var
- [=] 值传递的方式捕获所有父作用域的变量,包含this
- [&var] 引用传递的方式捕获变量var
- [&] 引用传递的方式捕获所有父作用域的变量,包含this
- [this] 值传递的方式捕获this指针
并且可以通过一些组合表示复杂的意义
e.g.,[=,&a,&b]
: 引用传递的方式捕获变量a和b,值传递的方式捕获其他变量。
lambda与仿函数
仿函数一般又称作函数对象,简单来说就是重定义了成员函数operator(),的一种自定义类型对象。
lambda与仿函数有相同的内涵:都可以捕获一些变量作为初始状态,并且接受参数进行运算。
实际上仿函数是编译器实现lambda函数的一种方式。
- 在C++11中,lambda并不是仿函数的完全替代者,很大程度上是因为lambda的捕捉列表的限制造成的,现有的标准中,捕捉列表仅仅能捕获父作用域的自动变量,对于超出此范围的变量是不予捕获的,
- 而仿函数可以被定义在不同作用域范围内取得初始值,因此可以跨作用域共享。
总的来说lambda被设计的目的就是为了要就地书写就地使用。
lambda仿函数与函数指针
class Test{
pubilc:
static bool greate(const ListNode* a,const ListNode* b){
return a->val>b->val;
}
class Cmp{
public:
bool operator()(const ListNode* a,const ListNode* b){
return a->val>b->val;
}
};
int getMin(){
priority_queue<ListNode*,vector<ListNode*>,decltype(*greate)> pq1(*greate);
//用函数指针的
auto cmp=[](const ListNode* a,const ListNode* b)->bool {return a->val>b->val;}
priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)> pq1(cmp);
//用lambda
priority_queue<ListNode*,vector<ListNode*>,Cmp> pq;
//用仿函数的
}
};