《C++11/14高级编程Boost程序库探秘》之第1章全新的C++语言(三)学习记录
1.7函数式编程
函数式编程是与面向过程编程、面向对象编程和泛型编程并列的一种编程范式,它基于λ演算理论,把计算过程视为数学函数的组合运算。
1.7.1 lambda表达式
基本形式为:
[](params){...}
[]称为lambda表达式引出操作符,圆括号里是函数的参数,花括号内则是函数体,可以使用任何C++语句。
lambda表达式的类型称为闭包,无法直接写出,所以通常需要使用auto的类型推导功能来存储。示例如下:
[[email protected] C++11]# cat lambdademo.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
auto f1 = [](int x)
{
return x*x;
};//表达式结束,语句末尾需要用分号
auto f2 = [](string s)
{
cout<<"lambda:"<<s<<endl;
};
auto f3 = [](int x, int y)
{
return x<y;
};
int main()
{
cout<<f1(3)<<endl;
f2("lambda demo");
cout<<f3(1,5)<<endl;
vector<int> v = {1,3,5,7};
for_each(v.begin(), v.end(), [](int x){cout<<x<<",";});
for_each(v.begin(), v.end(), [](int& x){if(x>3){x *= 2;}});
return 0;
}
[[email protected] C++11]# g++ lambdademo.cpp -o lambdademo -std=c++11
1.7.2 捕获外部变量
lambda表达式的完整声明语法是:
[captures](params) mutable->type {...}
captures被称为捕获列表,可以捕获表达式外部作用域的变量,在函数体内部直接使用,这是与普通函数或函数对象最大的不同之处。
捕获列表里可以有多个捕获项,以逗号分隔,规则如下:
[] :无捕获,,函数体内部不能访问任何外部变量
[=] :以值(拷贝)的方式捕获所有外部变量,函数体内部可以访问,但是不能修改
[&] :以引用的方式捕获所有外部变量,函数体内可以访问并修改(需当心无效引用)
[var] :以值(拷贝)的方式捕获某个外部变量,函数体内部可以访问,但是不能修改
[&var] :以引用的方式捕获某个外部变量,函数体内可以访问并修改
[this] :捕获this指针,可以访问类的成员变量和成员函数
[=,&var] :引用捕获变量var,其他外部变量使用值捕获
[&,var] :值捕获变量var,其他外部变量使用引用捕获
lambda表达式还可以使用关键字mutable修饰,它为值方式捕获添加了一个例外情况,允许变量在函数体内也能修改,但这只是内部的拷贝,不会影响外部的变量,示例如下:
[[email protected] C++11]# cat lambda_multable_demo.cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int x = 0;
auto f1 = [=]() mutable {return ++x;};//仅在内部修改,不影响外部变量
f1();
cout<<"multable x:"<<x<<endl;
//auto f2 = [=](){return ++x;};//编译错误,increment of read-only variable ‘x’
//f2();
//cout<<"value x:"<<x<<endl;
auto f3 = [&](){return ++x;};
f3();
cout<<"ref x:"<<x<<endl;
return 0;
}
[[email protected] C++11]# g++ lambda_multable_demo.cpp -o lambda_multable_demo -std=c++11
[[email protected] C++11]# ./lambda_multable_demo
multable x:0
ref x:1
1.8 并发编程
线程本地存储是指变量在进程里拥有不止一个实例,每个线程都会拥有一个完全独立的,线程本地化的拷贝,多个线程对变量的读写互不干扰,完全避免了竞争、同步的麻烦,示例如下:
[[email protected] C++11]# cat thread_local_demo.cpp
#include <iostream>
#include <algorithm>
#include <thread>
using namespace std;
int main()
{
extern int x;
static int y = 0;
thread_local int z = 0;
auto f = [&](){++y;++z;cout<<y<<","<<z<<endl;};
thread t1(f);
thread t2(f);
t1.join();
t1.join();
cout<<y<<","<<z<<endl;
return 0;
}
[[email protected] C++11]# g++ thread_local_demo.cpp -o thread_local_demo -std=c++11 -lpthread
[[email protected] C++11]# ./thread_local_demo
./thread_local_demo: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.22‘ not found (required by ./thread_local_demo) //在Redhat7.3未升级glibc的情况下是不支持thread函数的,需要升级glibc的版本才行。
实际线程t1的输出为1,1 实际线程t2的输出为2,1 实际主线程的输出为2,0
thread_local的变量的生命周期比较特殊,它在线程启动时构造,在线程结束时析构,即仅在线程的生命周期内是有效的。
thread_local仅适用于线程需要独立存储的情况,当线程间需要共享资源访问时仍然需要使用互斥量等保护机制。
1.9 面向安全编程
1.9.1 无异常保证
void func() noexcept {} //函数决定不会抛出任何异常
1.10 杂项
在C++98中,模板参数列表里不能出现两个连续的右尖括号>>,否则编译器会把它解释为右移运算符,这导致在写某些复杂的模板类时,模板参数列表末尾的多个>之间必须用空格分隔,但是在C++11/14中弥补了这个缺陷,在模板声明里遇到>>时,会优先解释为模板参数列表的结束标记。
原文地址:https://www.cnblogs.com/snake-fly/p/12622960.html