Two quick C++ questions concerning game engine design.

Started by
12 comments, last by wodinoneeye 15 years, 4 months ago
Hello, I have two quick C++ questions concerning game engine design. Question 1): In a large application requiring real time performance (such as a game) it is my understanding that allocations/deallocations (new delete new[] delete[] etc.) are bad if at all avoidable because they are slow. Perhaps allocations/deallocations during load time are ok if necessary for performance purposes. It is also my understanding that simple stl containers use the operators new/delete by default. Which would be your recommendation for using such containers in a game engine ... 1)Avoid stl containers completely and write ones own. 2)provide custom allocator(s) for stl (such as a memory manager). Question 2): Syntax question about C++. Ok, so this is in design phase so I am only 90% sure this is even possible, but what I would like to do is to have a function pointer as an argument to a template class (Foo in this case). Something like : template< void (*pCullFnc)(int i) = NULL> class Foo { ... }; I would then like to pass the METHOD of a different class as the template argument to Foo. I know how to use function pointers and to pass function pointers etc. but I do not know how to pass methods as function poiners in this case or if this is even possible.
Advertisement
Quote:Original post by grill8
In a large application requiring real time performance (such as a game) it is my understanding that allocations/deallocations (new delete new[] delete[] etc.) are bad if at all avoidable because they are slow. Perhaps allocations/deallocations during load time are ok if necessary for performance purposes.
Allocation and deallocation are slow, which means that you shouldn't use them too frequently (in terms of time, not in terms of code). If 80% of your time is spent in 20% of your code, then you should probably avoid dynamic allocation in those 20% (don't allocate memory on every frame for every polygon you render) but the other 80% of your code are fair game.

Quote:1)Avoid stl containers completely and write ones own.
2)provide custom allocator(s) for stl (such as a memory manager).

3)Use std::vector and reserve the memory you expect to be using ahead of time.

Quote:but what I would like to do is to have a function pointer as an argument to a template class (Foo in this case). Something like :

template< void (*pCullFnc)(int i) = NULL>
No. What you can do is create a structure with a static function "cull", and pass that structure as a template argument:

template<typename Func> class foobar {  // ...  Func::cull(args);  // ...};struct MyCulling {  static void cull(params) {}};


Quote:I would then like to pass the METHOD of a different class as the template argument to Foo. I know how to use function pointers and to pass function pointers etc. but I do not know how to pass methods as function poiners in this case or if this is even possible.
It doesn't make any sense. A method is a message that is sent to an object, which means that you cannot call a method without specifying what object should receive the message.
note that this is also a new/delete for "bar"

int main()
{
while (true) bar();
return 0;
}

void foo()
{
int bar;
....
}

A lot of performance can be gained by turning on visual studios small block allocator or write your own memory manager.

A lot of game developers also have custom (and more efficient) versions of stl library. (like own implementation of vector etc) It could be worth to do, but i would try with stl and profile before doing these kinds of optimizations now ;)
www.ageofconan.com
Quote:Original post by _Kami_
note that this is also a new/delete for "bar"

int main()
{
while (true) bar();
return 0;
}

void foo()
{
int bar;
....
}
I don't understand what you're saying. In your code, 'bar' seems to be an auto variable in function 'foo' (allocated on the stack without the overhead of new/delete) but is used as a function in 'main'...
Quote:Original post by grill8
In a large application requiring real time performance (such as a game) it is my understanding that allocations/deallocations (new delete new[] delete[] etc.) are bad if at all avoidable because they are slow.


These operations run at same clock speed as other instructions. They're no slower. They may however be costly.

Quote: Perhaps allocations/deallocations during load time are ok if necessary for performance purposes. It is also my understanding that simple stl containers use the operators new/delete by default.


You don't know that. And you won't know where your bottle-necks are, until you have solved the problem, ideally several times, using alternate solutions.

There is a case to be made for pre-allocating memory, but that is orthogonal problem to stl containers. This can be achieved either by manually allocating resources, through allocators, smart pointers, handles, cursors or other techniques.

Also, memory management on PC is considerably lesser issue than on embedded systems.

3)
template< void (Foo::*fp)(int) > class Func {}// ortemplate < class T, class R, class P1, R (T::*fp)(P1) > class Func {}

Also, boost::bind.

Quote:Original post by grill8
1)Avoid stl containers completely and write ones own.
2)provide custom allocator(s) for stl (such as a memory manager).


Avoid writing your own containers from scratch. If your profiling shows that memory de-/allocation is the issue, try writing your own allocators. Or read 'Modern C++ Design'.
Some libraries allocate a big chunk of memory at the start and use that as their memory pool. Be careful with fragmentation and leaks though.

hth,
CipherCraft
Awesome ... groovy.

Thank you.
Jeremy
Quote:
I don't understand what you're saying. In your code, 'bar' seems to be an auto variable in function 'foo' (allocated on the stack without the overhead of new/delete) but is used as a function in 'main'...


yeah, you are right. foo is on the stack, while bar is on the heap (more expensive)

But the behaviour is the same, constructor and dtor are still called (this is why it can be a bad idea for initialize xyz to 0 in a vector3 constructor).

Anyway, For Question 1 i would go with 1, especially if you are on a memory limited platform like xbox or ps3 where memory fragmentation can be a killer.
www.ageofconan.com
Quote:Original post by _Kami_
yeah, you are right. foo is on the stack, while bar is on the heap (more expensive)
'foo' is a function, so it's not allocated (arguably, its code has to exist somewhere, but this is neither on the heap nor on the stack). 'bar' is also a function (same reasoning), but it is a local variable as well (so it's on the stack). Your example contains no heap allocations.

Quote:But the behaviour is the same, constructor and dtor are still called (this is why it can be a bad idea for initialize xyz to 0 in a vector3 constructor).
The expected behavior of the default constructor is to default-construct values—namely, to initialize them with a known default value. Of course, in the extremely rare situation where you wish to define a value without initializing it (this only happens in heavily optimized algorithms) you can provide a constructor for that purpose that is not the default constructor and will simply be optimized away by the compiler.
ToohrVyk:
lol, no wonder i'm confused. the example i posted here isnt the one I thought i posted!

this is what i meant:
#include <iostream>using namespace std;class someobject{ public:  someobject() {std::cout << "Ctor\n"; }};void foo(){  someobject a;}void bar(){ someobject* a = new someobject(); delete a;}int main (){  foo();  bar();  return 0;}


Now it should make more sense. variables in foo is on stack, while vars in bar is on heap. Anyway, my point was that behaviour was exactly the same.

I still belive having a default constructor for vector3 that inits stuff to 0 is silly, especially since this is something that is called often, and you rarely want to use what the default gives you ayway.

All stl containers will use the () constructor, for example, before copying over the members, so if you are doing work in the () constructor you are basically wasting a lot of cycles just setting memory to 0 when it will get a different value immidiatly. And I certainly find
 vector3 vect(0.0f, 0.0f, 0.0f);

more readable and understandable than
 vector3 vect;  // what kind of hidden voodoo goes on here?

Basic types does not get an initial value (0) as well.

This is certainly something to have in mind when designing an engine.
www.ageofconan.com

This topic is closed to new replies.

Advertisement