后现代的系统编程语言
C++作为一门经典的编程语言,从上世纪八十年代起至今一直被广泛应用在系统开发和高性能计算领域。近几年来随着各种编程语言和范式的兴起,C++的身影渐渐淡出了人们的视野。但是作为一个仍在不断进步的语言,C++在最近几年飞速发展,已经具备了现代语言应有的特性,而且也有了许多已有的和正在进行的新的拓展。
经典的C++
作为C语言的超集,一方面,C++集成了C在系统编程优点,能够精确的控制内存中的每一个bit;另一方面,提供了丰富的抽象机制和编程范式,引入了面向对象、泛型编程和函数式编程等风格。因为这一点,C++拥有了与C媲美的运行时性能,另一方面,也简化了C语言带来的领域建模的难度。但是因为C++的整体设计结合了多种风格,几乎相当于嵌套了几个小语言的一个庞大的系统,这也使得C++的整体易学性和易用性上有些差劲。同时,由于标准库更新跟不上需求,在诸如Concurrency/Network等应用层的软件设计方面逐渐被Java等后来者取代。而且,各个C++厂商对编译器的实现并没有完全参考ISO标准,也造成了很多跨平台可移植性和兼容性问题。
现代C++
C++在最近几年进行了几次探索和蜕变,让整个语言变得更具备现代化的特色。
资源管理
RAII(Resource Aquiration is Initialization,资源获取即初始化)作为C++的特色之一,被广泛地应用到C++的程序中。RAII通过堆对象的生命周期来控制资源(包括堆内存、文件句柄、网络连接等)的生命周期,使得资源管理变得更加自动化,同时也避免了引入垃圾回收带来的运行时负担。但这种模式有一个很重要的问题,就是当需要对资源进行共享时,需要做更多额外的工作来进行检查和同步等工作。
作为更现代的资源管理方式,C++11中引入了两种智能指针,std::shared_ptr和std::unique_ptr。前者拥有线程安全的引用计数,后者则是通过所有权(owenrship)转移来控制资源的生存周期。C++11中也引入了右值引用和移动语义,来避免资源传递的过程中的不必要的复制。
与Rust中的生命周期(Lifetime)和所有权(Ownership)的概念类似,C++的std::unique_ptr在每一次值传递的时候将自身持有的资源转移到赋值的目标,同时结合移动语义,将赋值过程进一步地优化。
Lambda
Functor作为C++ STL的一个重要组件,也是C++中被使用很多的一个功能。一个Functor其实就是一个重载了operator()的类的实例对象,这种对象配合C++模版的行为,可以被简单看成一个函数来调用,所以被称为Functor(函子)。但是,由于C++对于匿名类和内部类支持并不够好,使用Functor必须提前进行设计。一方面不方便使用,另一方面,定义和使用分离,对代码的组织和理解也造成了一定的困难。
首先,lambda作为Functor的替代品,解决了不能即时定义并使用的问题。配合STL中的容器和算法,lambda也能将C++的函数式风格发挥到极致。其次,出于C++一贯对性能和抽象的考虑,引入了lambda capture的概念,使得对象的生命周期能够绑定到lambda表达式,也就能够构建出闭包对象(closure)。另外,C++14中加入的generic lambda,增强了lambda的类型推导算法,在不损失类型安全特性的基础上,让组合式编程(Combinator–based Programming)更加易于实现。
并发
在C++设计的初期,并发并未作为核心的语言特性考虑在内。并且,线程等并发模型在不同平台之上也有各种不同的实现,构建一个统一的并发模型也很困难。
C++11中重新设计了C++的内存模型,在保持原有兼容性的基础之上加入了并发的内容。同时标准库中也加入了线程(<thread>)、信号量(<condition_variable>)、互斥锁(<mutex>)和原子操作(<atomic>)等内容。同时也在此基础上封装了future/promise模式和async等操作。
元编程
C++自身对元编程提供了良好的支持。作为主要组件之一的模版,提供了编译时的数值计算和类型计算。但一方面由于使用模版减慢编译速度,另一方面,在使用模版的时候,非常难以调试和排错,这让很多人望而却步,甚至对基于模版的STL组件也有一种畏惧感。
C++11中对元编程支持做了加强。首先是把type traits作为标准库引入,能够给模版提供一套直观的约束,也让类型作为C++中的第一类值(first-class value)存在;另外constexpr的引入简化了编译时的值运算,配合用户自定义字面量(user-defined literals)以及可变参数模版(varadic template/parameter pack)等特性,让C++能够更方便地定义内部DSL。
Bright Future
作为一门经典的编程语言,C++至今还在不断地更新着。即将到来的C++17中,正在筹备着这些重要的特性:
-更丰富的标准库:C++中对File System、Network等重要的组件进行了标准化的支持,
-Module TS:模块化提案,用于替代继承自C语言的头文件,简化C++的编译模型和模块依赖,
-Concepts TS:用于增强类型约束和类型推导,同时也简化模版的用法,
-Reflection TS:提供编译期静态反射的支持,简化和增强type traits,提供更丰富的元编程功能。
Conclusion
可以看到C++发展至今一直都走在时代的前列线上。一方面,增加了更多适合应用和系统开发的组件,另一方面,通过语言特性的扩充来简化抽象复杂度。作为这样一个兼具新生特性和历史责任的编程语言,足以预见其应用的广度;同样,更多的系统级开源项目,像Mesos等,也选择C++作为主要的编程语言。有足够的理由让我们相信,C++正在重获新生。