C++ part8
1、volatile关键字
在C++中,对volatile修饰的对象的访问,有编译器优化上的副作用:
- 不允许被编译器优化,提供特殊地址的稳定访问(只从内存中读取)。
- 有序性,编译器进行优化时,不能把对volatile对象前面的其他volatile语句放到他后面,反之也不行。也就是说volatile变量间的操作,是不会被编译器交换顺序的。
注意:
在多线程数据同步时,很多人会选择volatile来修饰全局的变量,使得线程同步。其实是不对的。由有序性可得,编译器可能对语句的位置进行交换,使得程序错误。
volatile bool flag = false;
//线程1
while(flag == false){
done();
}
//线程2
update(); //语句1
flag = true; //语句2
上述代码中,编译时语句2可能和语句1调换位置,在多线程中,这可能会发生错误。
2、内联函数和宏定义
宏定义由预处理器实现,做一些简单的字符替换。
内联函数(inline)使用时,编译器将使用函数代码替换函数调用,这样就节省了函数调用的时间,但是增加了内存空间。
区别:
- 宏定义不能进行数据类型的检查,内联函数可以
- 宏定义展开发生在预编译阶段,内联函数展开发生在编译阶段
- inline作为类的成员函数可以调用类的对象,宏定义因为是文本替换,不可以
不适合使用内联函数的情况:
- 当inline内出现for,while时,函数的运行时间就比函数调用时间多出很多,那么使用inline的效率就很低,相反需要付出内存空间。
- inline不能使用递归。
- 函数体比较长,会消耗大量内存空间。
- 构造函数和析构函数不适合作为内联函数使用,因为编译阶段编译器会往构造和析构函数中额外加很多代码,比如申请/释放内存,初始化成员对象等等,可能代码并不精简。
3、Lambda
lambda表达式在其所在的位置上定义了一个匿名函数对象。
lambda表达式的形式:
[捕获值列表] (函数参数) mutable / exception -> 返回值类型
捕获值列表:分为值捕获,引用捕获。捕获的参数是我们能直接在函数体中使用的参数。和一般的函数不同的是,值捕获的值是在lambda创建时捕获的,也就是说在lambda创建后再改变值不会改变lambda内的捕获的值。
//example1
int a = 1;
auto fun = [a](){ return a; };
a = 11;
std::cout << fun(); //1
//example2
int a = 1;
auto fun = [&a](){ return a; };
a = 11;
std::cout << fun(); //11
函数参数:表示匿名函数的参数。
返回值类型:return的类型,void可以忽略。
函数体:函数的主体。