2023年6月10日 星期六

C++:利用 function dispatch 優化 Type Erasure 的效能

本文為 C++ Software Design 書的第 33 節內容。

前文簡介了 Type Erasure,而本文將介紹使用 function dispatch 的方法優化 Type Erasure 的效能。 前文的例子中 ShapeConcept 為一個抽象類別,裡面的函數為 virtual function。Function dispatch 的目的是手動加入 virtual dispatch,優化 virtual function 中找到真正函數了兩個步驟變成一個步驟。 以下為實作的例子:

class Shape {
public:
  template <typename ShapeT, typename DrawStrategy>
  Shape(ShapeT shape, DrawStrategy drawer)
    : pimpl_(new OwningModel(std::move(shape), std::move(Drawer)),
      [](void* shapeBytes){
        using Model = OwningModel<ShapeT,DrawStrategy>;
        auto* const model = static_cast<Model*>(shapeBytes);
        delete model;
      })
    , draw_([](void* shapeBytes) {
        using Model = OwningModel<ShapeT,DrawStrategy>;
        auto* const model = static_cast<Model*>(shapeBytes);
        (*model->drawer_)(model->shape_);
      })
    , clone_([](void* shapeBytes) {
        using Model = OwningModel<ShapeT,DrawStrategy>;
        auto* const model = static_cast<Model*>(shapeBytes);
        return new Model(*model);
      })
    {}

private:
  template <typename ShapeT, typename DrawStrategy>
  struct OwningModel {
  	OwningModel(ShapeT value, DrawStrategy drawer)
      : shape_(std::move(value))
      , drawer_(std::move(drawer)) {}
    ShapeT shape_;
    DrawStrategy drawer_;
  };
  
  using DestroyOp = void(void*);
  using DrawOp    = void(void*);
  using CloneOp   = void*(void*);
  
  std::unique_ptr<void,DestroyOp*> pimpl_;
  DrawOp* draw_;
  CloneOp* clone_;
};
主要的細節為將 virtual function 轉化成 void* 的函數,再用 static_cast 轉型成 OwningModel 的類別。根據書中的實驗結果,使用此技巧後大概能將效能提高 25%。