都要2021年了,現代C++有什麼值得我們學習的?

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++20 中,具備着這些重要的特性:

更豐富的標準庫:C++ 中對 File System、Network 等重要的組件進行了標準化的支持,

Module TS:模塊化提案,用於替代繼承自 C 語言的頭文件,簡化 C++ 的編譯模型和模塊依賴,

Concepts TS:用於增強類型約束和類型推導,同時也簡化模版的用法,

Reflection TS:提供編譯期靜態反射的支持,簡化和增強 type traits,提供更豐富的元編程功能。

總結

可以看到 C++ 發展至今一直都走在時代的前列線上。一方面,增加了更多適合應用和系統開發的組件,另一方面,通過語言特性的擴充來簡化抽象複雜度。作爲這樣一個兼具新生特性和歷史責任的編程語言,足以預見其應用的廣度;同樣,更多的系統級開源項目,像 Mesos 等,也選擇 C++ 作爲主要的編程語言。有足夠的理由讓我們相信,C++ 正在重獲新生。

 

 

看到這裏你是不是對「C++」又有了一點新的認知呢~

如果你喜歡這篇文章的話,動動小指,加個關注哦~

如果你也想成爲程序員,想要快速掌握編程,這裏爲你分享一個學習企鵝圈子

裏面有資深專業軟件開發工程師,在線解答你的所有疑惑~C++入門「so easy」

編程學習書籍:

 

編程學習視頻: