[C++] 提升程式效率的小方法

Rainie
職場學習筆記
Published in
4 min readAug 25, 2021

在開發 feature 的過程,除了功能正確,效能優化應該是每個工程師相當重視的課題,優化不只包含了演算法、流程、架構等大方向的改良,如果能在日常寫 code 時改變一下寫法,不知不覺中也能提升不少效能喔!

這篇文章用來記錄我收集來的幾個提升程式效率的小方法,分享給同樣寫C++的朋友,之後如果有收集到其他小技巧會持續更新這篇文章 😃

  • 參數傳遞時盡量使用 call by reference

通常來說,參數在沒特別指定的情況下傳遞給函式時,會以 call by value 的方式,也就意味者程式會呼叫 copy constructor 產生一個參數的副本傳入。而當函式返回時,這個臨時的副本也會隨之消滅並呼叫相對應的 destructor ,當物件變得相當巨大且複雜時,傳遞參數的成本會變得相當昂貴。

為了避免效能受到影響,如果傳遞參數的類型不屬於 built-in types 、iterator 、function object ,就盡量使用 call by reference 吧!

  • 使用 std::move 當你需要將資源轉移給其他人

在C++11之前,如果想要把變數資源轉移給另一個物件,只能透過 copy constructor,先產生不必要的臨時對象,複製完後再將此臨時物件銷毀。而透過 C++11 提供的 std::move 可以將 lvalue 轉換成 rvalue reference,以便後續呼叫物件的 move constructor 進行轉移,避免產生副本的成本。

現在大部分的 container 都已經提供 move constructor method,需要把資源轉移時不妨使用 std::move 的方式傳入。

  • 多使用直接初始化

簡單來說,賦值初始化會比直接初始化多創建一個臨時物件,不過似乎在沒有編譯器最佳化的情況才會有差異,大家可以視情況使用。

  • 挑選適合的資料結構

不同的資料結構或演算法之間可能會忽相牴觸,最常見的就是空間與時間的取捨,在決定演算法時,這是工程師得時刻面臨到的權衡問題。

以資料結構為例,C++ 提供了非常多的 container,每個 container 有各自的特性,包含元素是否需要保持順序 ( vector or set)、是否可接受重複數據 ( map or set ), 是否需要考慮插入與查詢的效率。

開發程式時必須先了解工具的特性才能選擇最適合的一種來解決問題!

  • 善用智慧指標

在還沒有智慧指標之前,必須仰賴工程師自己 new/delete 資源,然而在開發過程中很容易因為一時疏忽導致程式記憶體洩漏,智慧指標可以大幅降低開發過程中鬼遮眼的情況。

使用智慧指標建立物件時,可以使用 make_unique、make_shared 的方式,效率會比使用 new 還來的好,因為少掉了一次物件的建立。

另外,像是 handle 這種 windows 的核心物件,使用完畢必須把相關的資源釋放,針對這類型的資源管理,除了透過 RAII 模式去確保資源的安全性,也可以使用智慧指標實作喔!

  • Pimpl 減少編譯相依性

當你需要縮短整體專案編譯時間時,透過 Pimpl 技術可以把 private 成員封裝起來,透過指標的方式存取。這樣一來,header 不須 include 跟私有成員相關的檔案,除了減少專案的耦合,也避免了私有成員產生變動時,與之相關的所有 cpp 檔得跟著重新編譯。

  • 使用更好的 library

目前許多開源專案提供許多效率更好且更易於使用的 library,像是c++11 部分引入的 boost 就提供很多比原生還好用的檔案系統與演算法,或是你的程式需要高性能的平行需求時,可以考慮採用 intel TBB 開發等等。

比起再造輪子,好好善用網路資源,根據自己的開發需求選擇最適合的工具,不論是 ML、 UI、Graph 等各種領域,都可以搜尋到好用的開源庫。熱門的開源庫大部分也能找到相關的效能跑分與優缺比較,可以根據自己的開發需求做選擇。

如果以上有不正確需要修正的部分,或是你們也有一些小技巧可以跟我分享的,歡迎大家底下留言一起交流~

--

--