C/C++的那些小知识点

“Short-Circuit” Evaluation

在进行逻辑运算时,如果表达式已经能够确定最终值时,不再继续进行计算.
这减少了一定的计算量并且避免了错误的访问和计算.

bool a = true,b;
int c = 0;
b = a || ++c > 0;
printf("%d %d\n",b,c);

输出将会是1 0,因为a已经是true了,故而进行短路,不再往后执行,不执行++c.

这一特性可以用在如下场景来避免除0引发错误:

int a,b;
scanf("%d%d",&a,&b);
if(b != 0 && a % b == 0)
    printf("%d is a multiple of %d", a, b);
else
    printf("Something wrong.");

Lambda Expression

Lambda 表达式在很多其他语言中都有过使用了,如python中的func = lambda x: x + 2,又或者在JavaScript中的let func = (a) => a + 2;,甚至在C#中见到的Func<int,int> add = a => a + 2;都是Lambda 表达式.它在这些语言中都有自己的位置,这也侧面展现出它的重要,于是在C++11的标准中,C++也支持了Lambda 表达式.

Lambda 表达式表示的是一种匿名的函数,有时一个极其简单的函数(甚至不配拥有姓名)或者是一个作为参数传递的函数,当给它单独起名字不方便或者使用上遇到一些不确定性,Lambda 表达式就派上了用场.它的确是个函数,只是不配拥有姓名.

这里有几个递归函数的例子:

auto gcd = [&](long a, long b) -> long { return a % b == 0 ? b : gcd(b, a % b); };
auto Fibonacci = [&](int a) -> long long { return (a == 1 || a == 2) ? 1 : Fibonacci(a - 1) + Fibonacci(a - 2); };
auto Factorial = [&](int a) -> long long { return (a == 1) ? 1 : Factorial(a - 1) * a; };

在最新的C++20标准中Lambda 表达式的基本形式可以写为:

[ captures ] < tparams > ( params ) specifiers exception attr -> ret requires { body }

或者简写为:

[ captures ] ( params ) -> ret { body }

  • captures:捕获列表。前面的例子中[&]表示按引用捕获,还可以是[=]按值捕获。
  • tparams: 类型参数。在最新的C++20标准中添加。
  • params:和普通函数一样的参数。
  • specifiers:只有这个Lambda 表达式是mutable的才允许修改按值捕获的参数。
  • exception:异常标识。
  • attr:属性标识。初学者暂时不必理解。
  • ret:返回值类型,可以省略,让编译器通过 return 语句自动推导。
  • requires: 向闭包类型的operator()添加制约。初学者暂时不必理解。
  • body:函数的具体逻辑。

此处相关细节内容从略,可参考如下页面:
现代 C++:Lambda 表达式
Lambda 表达式
Lambda expressions

C++ Multithreading

C++11的更新中还有一个引人注目的地方在于关于多线程的更新,让利用C++编写多线程应用变得十分容易.(当时不知道我真的是孤陋寡闻)

本想着直接操作线程,在寻寻觅觅了<thread><future>之后,发现std::async提供的功能让任何人都可以十分容易的实现基础的多线程功能.

对于多线程的含义、意义、futurepromise的关系及其实现原理等等的详细问题这里先从略,读者若好奇建议自行查阅,这里只做简单使用层面的说明和记录.

//设 func 是以 args 为参数返回值为 vector<int> 的函数
int thread_count = 16;

vector<std::future<int>> futures;//存放 future 对象

vector<int> result;

for (int i = 0; i < thread_count; ++i)
    futures.push_back(std::async(std::launch::async,func,args));//创建线程

for (int i = 0; i < thread_count; ++i)
{
    vector<int> part_result = futures[i].get();//等待线程并获取结果
    result.insert(result.end(), part_result.begin(), part_result.end());
}