自己常用的C/C++小技巧
?
這里列出了自己常用的一些c/c++小技巧, 有些會有不足, 可以簡單探討一下.
32位/64位等 分類
分類: 小技巧
同理可以用于其他位, 比如16位什么的. 由于不同位的平臺指針的大小可能是不同的, 所以導致一些邏輯必須分別討論.
很多時候我們可能不會在意是移動平臺還是桌面平臺, 但是肯定會在意指針的大小. c++的話可以使用模板特化方便地處理, 模板特化也是c非常難以模擬的特性之一.
最簡單的, 比如我們想在32位平臺是用單精度浮點而64位平臺使用雙精度浮點:
template<int T> struct float_helper_t{ };template<> struct float_helper_t<4> {using float_t = float; };template<> struct float_helper_t<8> {using float_t = double; };using mfloat_t = float_helper_t<sizeof(void*)>::float_t;零代價pimpl
分類: 隱藏實現, 零代價
pimpl很好用, 但是不是零代價的. 不過對象大小是在編譯器是固定(c++), 我們可以利用c++11的std::aligned_storage創建一個零代價的pimpl. 同時針對不穩定API可以用static_assert進行編譯期斷言.
例如WinAPI有一個SRWLOCK, 表面上是一個指針. 雖然我們可以用指針重解釋, 但是作為例子可以這么實現:
// 頭文件namespace detail {template<size_t> struct rwlocker_impl_info {};template<> struct rwlocker_impl_info<4> { enum { size = 4, align = 4 }; };template<> struct rwlocker_impl_info<8> { enum { size = 8, align = 8 }; }; }class CRWLocker {enum { buf_size = detail::rwlocker_impl_info<sizeof(void*)>::size };enum { buf_align = detail::rwlocker_impl_info<sizeof(void*)>::align }; protected:std::aligned_storage<buf_size, buf_align>::type m_impl; };// 源文件// 最好進行編譯期斷言CRWLocker::CRWLocker() noexcept {// WinAPI 的SRWLOCKusing ui_rwlocker_t = SRWLOCK; static_assert(sizeof(ui_rwlocker_t) == buf_size, "must be same");static_assert(alignof(ui_rwlocker_t) == buf_align, "must be same");const auto locker = reinterpret_cast<ui_rwlocker_t*>(&m_impl);::InitializeSRWLock(locker); }對于不穩定的API, static_assert是非常重要的.
鏈表多態
分類: 實現技巧
基礎數據結構中, 鏈表由于是指針的重要體現, 可以非常方便地處理多態:
------ ------ ------node --> node --> node ------ ------ ------ data#1 data#2 data#3 ------------------例如比較常用的"工廠模式"創建的各個對象可以用鏈表串起來:
struct Node {Node* prev;Node* next; };struct Factory {Factory();Node head;Node tail; };struct Obj1 : Node {int a; };struct Obj2 : Node {float a; };Factory::Factory() {head.prev = nullptr;head.next = &tail;tail.prev = &head;tail.next = nullptr; }每次添加節點可以在Factory::tail.prev處做文章. 刪除節點由于有頭節點與尾節點的存在非常簡單:
node.prev->next = node.next; node.next->prev = node.prev;多態的實現, 一般來說就是c++使用的虛函數. 不過注意的是虛表指針會占用一個指針的空間, 所以和節點的布局可以有兩種:
A {vtable*;node; };B {node;vtable*; };一般選用A模式, B比較難實現. A模式又有一個面向對象常有的問題: 包含, 還是繼承?
c++有一些自己不喜歡的東西, 這些東西都是屬于, 對程序猿隱藏. A模式使用繼承的話, static_cast轉換Node和繼承類會隱含一個偏移判斷, 這個隱藏沒有問題. 問題是轉換前會對指針進行判斷, 如果是nullptr的話, 轉換后還是nullptr, 這個很合理但是自己不喜歡, 添加了一個隱藏的分支.
如果大家對C/C++感興趣的話,可以加一下我們的學習交流Q群:637 ?935 ?295,免費領取一套學習資料和視頻課程喲~
所以自己可能會使用"包含"模式, 再使用offsetof進行手動轉換, 雖然offsetof對于非標準布局是UB行為, 但是實際上不是offsetof是UB, 而是非標準布局.
總結
以上是生活随笔為你收集整理的自己常用的C/C++小技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第14课:项目实战——深度优化你的神经网
- 下一篇: 第12课:优化神经网络——网络初始化技巧