After I read (long) articles about custom allocators :-
- http://www.dice.se/news/scope-stack-allocation/
- http://gamesfromwithin.com/start-pre-allocating-and-stop-worrying
and did some simple testing, I realized that they can vastly improve performance of my software.
I feel that they are moderately-simple to be adopted in the most cases,
except in situation that a function want to return non-POD type.
Example
I create 2 systems SystemA
and SystemB
.
For simplicity, they are singleton and can be accessed globally.
SystemA* systemA;
SystemB* systemB;
Both system has it owns allocators for each type:-
class SystemA/SystemB{
Allo oneFrameAllo=oneFrameAllocator();
Allo heapAllo=heapAllocator();
};
By design, systemB
want to request likeReport* report=systemA->generateReport()
.
Example: SystemB
(AI-System
) query all enemy information from SystemA
(NPC-Manager
).
In SystemA::generateReport()
prefer to use its own allocator SystemA::oneFrameAllo
to do internal thing,
but systemB
expect a result that use SystemB::heapAllo
.
How to achieve that?
Note: In real case, Report
is a non-POD, so it is not convenient to return Report
by value.
Edit
Here is a compilable demo.
It uses "pass allocator as parameter" approach. (suggested by John Zwinck, thank!)
Only the essential part is shown here :-
class SystemA{
Allo oneFrameAllo;
Allo heapAllo;
public: Strong_Pointer<Report> generateReport(Allo* allo){
/* use the one-frame-allocator to do internal computation */
Strong_Pointer<int> some_temporary_variable=oneFrameAllo.allocate<int>();
*(some_temporary_variable.ptr)=5; //result of #1 above
Strong_Pointer<Report> r=allo->allocate<Report>();
r.ptr->someInfo = allo->allocate<int>();
*((r.ptr->someInfo).ptr)=*(some_temporary_variable.ptr);//#2
return r;
}
};
SystemA* systemA=new SystemA();
class SystemB{
Allo oneFrameAllo;
Allo heapAllo;
Strong_Pointer<Report> report;
public: void update(){
report=systemA->generateReport(&heapAllo);
}
};
SystemB* systemB=new SystemB();
I am still not sure if it is the right way.
Disadvantage:-
- It is dirty : additional parameter.
(minor) The function interface will become very allocator-aware :-
- If allocator is the first parameter : I can't make it default parameter in most case.
Otherwise, it interrupts existing function with default parameter e.g.
f(X x=X()){} -> call f() is OK become f(X x=X(),Allo* allo){} -> f( must insert X() manually, &allo)
Really, I have to add that single parameter to many function in existing code base.
Is it really ok?- (subjective) I have never found any code like this.
Another alternative is to let SystemB
creates a report that has field Allo*
,
and pass the &report
as a parameter of systemA->generateReport()
.
SystemA
will fill the report
. (Thank vu1p3n0x)
Please provide either a better way OR confirm that this approach is already good in general.
Then, provides some references to show that it is really a professional approach.