Re: [問題] 為什麼CRTP+variant還是比virtual快很多

看板C_and_CPP作者 (BestSteve)時間4年前 (2020/01/03 07:22), 4年前編輯推噓1(100)
留言1則, 1人參與, 4年前最新討論串2/2 (看更多)
使用virtual function的時候,每個class會多一個vtable儲存virtual function的 pointer: class Interface { public: virtual void f() = 0; virtual ~Interface() = default; int a; }; class Implement: Interface { public: void f() override {} int b; }; 通常的記憶體分布會長這樣: 0 1 2 3 4 5 6 7 8 0┌───────────────┐ │ &Implement::f │ 8├───────────────┤ │ &Interface::~Interface │ 16├───────┬───────┤ │ a │ b │ 24└───────┴───────┘ 在程式執行時要呼叫f的時候就是從vtable中拿到f的function位址來呼叫的,這就代 表有一次indirect call的時間成本。 return (*vtable[0])(); 使用variant儲存多種物件時,會像union一樣占用最大type所占用的空間+一個標示 type用的int。 template <typename Derived> class Interface { public: void f() {static_cast<Derived*>(this)->f();} int a; }; class Implement: Interface<Implement> { public: void f() {} int b; }; std::variant<Implement> V; 而variant儲存一個Implement時候的記憶體分布會長這樣: 0 1 2 3 4 5 6 7 8 0┌───────┬───────┐ │ type_index │ a │ 8├───────┼───────┘ │ b │ 16└───────┘ 其中type_index是代表目前內部儲存的type,-1是錯誤值,0是type list內第一個type。 使用visitor時,產生的程式碼會像這樣: switch (type_index) { case 0: return visitor(*reinterpret_cast<Interface*>(&storage)); default: throw std::bad_variant_access(); } 這裡執行時的成本為一或多個condition jump,與一個jump。總體所需時間略低於一個 indirection jump,而且還能受益於branch prediction,所以這裡使用variant會比使用 virtual function快得多。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 223.136.12.213 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1578007356.A.7A4.html ※ 編輯: ibmibmibm (223.136.12.213 臺灣), 01/03/2020 07:28:04

01/03 08:34, 4年前 , 1F
感謝詳細解說
01/03 08:34, 1F
文章代碼(AID): #1U3diyUa (C_and_CPP)
文章代碼(AID): #1U3diyUa (C_and_CPP)