cpp模仿C#事件機制(1) 無參數版實現

cpp模仿C#事件機制(1) 無參數版實現

  • githubpage 後續更新會快一些:https://puzzzzzzle.github.io

起因

  • 之前寫unity時,感覺c#的事件機制超好用,就想在萬能的c++中實現一下
  • 看了網上的一些實現,大部分都是隻能註冊一個回調函數的,這有啥用???
  • 要麼就是使用時要繼承一大堆東西,一點也不方便

設計

  • 本身很簡單,就是一個觀察者模式,麻煩的是對回調函數的管理
    • 需要一個容器存儲回調函數,set,vector都行
    • 要裝進容器中,那麼你的回調函數就要支持一些符號
  • 這裏實現了兩種事件發佈器
    • 基於std::unordered_set,重複插入會返回false,調用順序和插入順序無關
    • 基於std::vector,允許重複插入,調用順序和插入順序相同
  • 兩種事件發佈器都提供註冊常駐回調函數和一次性回調函數接口(擴展了下,還是有這方面的需求的)
  • 多線程只是簡單的分類鎖了下,有需要的話可以擴展各種無鎖生產者消費者模型或者由訂閱器維護回調函數,發佈器維護訂閱器引用
  • 回調函數過期
    • 回調函數已經被釋放會導致空指針問題,程序會core,c#中也有這個問題
    • 這裏儘可能解決下
      • 使用std::shared_ptr包裹回調函數,訂閱器自己必須維護ptr
      • 發佈器使用std::weak_ptr來指向回調函數
      • 已經過期的直接從隊列中刪除,報告下
    • 這樣就解決了大部分過期問題
    • 現存的問題
      • 當回調函數線程已經通過檢測了,準備調用,這時訂閱器被銷燬了,還會有問題
      • 如果再引入鎖的話開銷有些大,先這樣吧
  • 最終設計
    • 訂閱器使用std::weak_ptr<std::function<void()>>作爲回調函數
    • 發佈器使用std::shared_ptr<std::function<void()>>來保存回調函數引用
    • 有參數的,類中的方法,仿函數之類的使用std::bind包裝爲std::function<void()>

用法

  • [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qJc1pWEJ-
  • 在這裏插入圖片描述
  • 不需要任何繼承
  • 任何我能想到的c++調用方式都是支持的

實現

  • 本身挺簡單的,就是一個觀察者模式
  • 額外實現了
    • 多線程安全:使用鎖
    • 一次性任務:執行完成後刪除自身
    • 空指針任務拋棄:weak_ptr lock失敗的直接刪掉
  • 只需要給std::weak_ptr實現hash和equal函數就行
    • using DelegrateWeakSave = std::weak_ptr<std::function<void()>>;
      using DelegrateDefine = std::shared_ptr<std::function<void()>>;
      
      struct HandleBindHash {
          std::size_t operator()(DelegrateWeakSave const& ptr) const {
              if (auto spt = ptr.lock()) {  // 使用之前必須複製到 shared_ptr
                  return reinterpret_cast<size_t>(&(*spt));
              } else {
                  return 0;
              }
          }
          std::size_t operator()(DelegrateDefine const& ptr) const { return reinterpret_cast<size_t>(&(*ptr)); }
      };
      struct HandleBindEqual {
          bool operator()(const DelegrateWeakSave& lhs, const DelegrateWeakSave& rhs) const {
              return HandleBindHash()(lhs) == HandleBindHash()(rhs);
          }
      };
      
    • 這裏簡單使用地址作爲hash地址,由於是用shared_ptr來包裹std::function的,所以沒問題
  • 剩下的就是一個觀察者模式了,沒啥說的

完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章