C1 , C2 , ... are callback classes.
They are derived from the CBase common interface with the CBase::f() .
They all override CBase::f() with the final modifier.
I need to register ~ 50 instances of any class derived from C1 , and ~ 50 instances of any class derived from C2 .
> (see @@ in the code below)
The main goal: When calling allF() you need to call C1::f() / C2::f() all registered instances.
Here is a simplified version, it works ( Full demo ): -
#include <iostream> #include <vector> class CBase{ public: virtual void f(){std::cout<<"CBase"<<std::endl;} }; class C1 : public CBase{ public: virtual void f() final{std::cout<<"C1"<<std::endl;} }; class C2 : public CBase{ public: virtual void f() final{std::cout<<"C2"<<std::endl;} };
This is callback registration: -
//-------- begin registering ----- std::vector<CBase*> cBase; void regis(CBase* c){ cBase.push_back(c); } void allF(){ //must be super fast for(auto ele:cBase){ ele->f(); //
Problem
According to the profile result, if I can avoid the cost of the v-table in # , I get a significant increase in performance.
How to do it elegantly?
My bad decision
Possible workaround: create multiple arrays to store each CX ( Full demo ): -
//-------- begin registering ----- std::vector<C1*> c1s; std::vector<C2*> c2s; void regis(C1* c){ c1s.push_back(c); } void regis(C2* c){ c2s.push_back(c); } void allF(){ //must be super fast for(auto ele:c1s){ ele->f(); //
It's very fast. However, this is not very good. After several developmental cycles, C3 , C4 , etc. were born.
I need to create std::vector<C3*> , std::vector<C4*> , ... manually
My approach leads to a follower of support.
Additional Information (Edited)
In the worst case, no more than 20 classes. ( C1 to C20 )
In the real case, C1 , C2 , ... are a special type of data structures.
All of them require special initialization ( f() ) at exactly the right time.
Their instances are built on different .cpp .
Thus, caching the array std::vector<CBase*> cBase; caching all of them would be helpful.
For example, C1 is map 1:1 , C2 is map 1:N , C3 is map N:N
Together with a custom dispenser, I can achieve unearthly data locality.
Note: I do not need the callback order. (Thanks Fire Lancer)