As I see it now, I should use stack vars if and only if it's life span does NOT need to exceed the scope of it's creation {}.
Also, a "little" advantage of heap vars is that I can free them in the "middle" of the scope, thus the memory usage is a little smaller.
Ok! I will use stack vars where I can !
Keep in mind that the examples you've looked at so far, these "stack allocated" objects have always been local variables, which means that they do exist on "the stack", and their scope is the scope of the function. However, functions aren't the only thing that have a scope.
For example:
struct Foo
{
int a, b, c;
};
struct Bar
{
Foo foo
};
void Test()
{
Bar barStack;
Bar* barHeap = new Bar;
delete barHeap;
}
The barHeap object is created on the heap, which mean that it's members are also created on the heap.
However, the foo member of Bar isn't a pointer or reference - it's a value member of Bar - the kind of variable we've been calling "stack variables". It's scope ({}'s) is the Bar object itself, which means that when the Bar object is created, the Foo is also created, and when the Bar object is deleted, the Foo is also deleted. They have the same lifetime. So instead of saying that foo has a "stack lifetime", it's better to say that it has an "automatic lifetime" (which means it's lifetime is the same as it's scope/{})
About shared_ptr. I read now that that Bjarne consider this as bad idea and this is considered as bad c++ design pattern. Anyone can put some light on this.
About unique_ptr. I do NOT want to write managed code. Is unique_ptr managed code ???
No, unique_ptr is not managed code, it's a part of the standard C++ library (it's full name is std::unique_ptr).
It's bad to use shared_ptr when you don't need such complexity. shared_ptr is for when you need reference counting.
If you don't need reference counting, and the object has only a single owner, then unique_ptr should be used.
And Norman, you're insanea complete troll if you seriously think you shouldn't use any dynamic memory allocation. Yeah, definitely a troll. Not even gonna try to respond to your post anymore.
The easiest way is to call malloc once to get a really large buffer, and then re-implement your own version of malloc that operates inside this buffer. Then you can still perform dynamic allocation (with similar costs to malloc) while saying that you never actually use malloc.
Yes that is a (mostly) sarcastic suggestion.
Seriously though, look at any game from the 90's or early 00's and it will be very rare to find any new/malloc usage within the game loop (i.e. outside of the loading/caching phase). It's definitely possible.
My engine is all C++ (and not the "C with classes" style of C++), but new is banned (a custom macro that wraps around placement-new is used in it's place), and malloc is used very rarely - usually to create large allocations which act as pools of specific objects (e.g. a pool of 1000 monsters that you can dynamically allocate/free from/to), or to create large allocations for scope/stack allocators. Not only is scope/stack allocation must simpler (faster) than new/malloc, but I personally find it to be less error prone and simpler to think about too (e.g. no leaks without even the hassle of using smart pointers).
Again, technically it's dynamic memory allocation, but it's not using new/malloc
Also, this is just for the engine. My game code is Lua, which mallocs excessively and is much slower than C++, but isn't performance critical
have a global array[MAXNPCS] with an active field in the struct
That's decent advice, but there's no reason it has to be a global. If you create it with malloc, then the cost of that allocation is amortized across every element, so it ends up being very cheap per each NPC, plus you only do it once so it's not a big deal even if it is expensive.
Also, the 'active' field probably shouldn't go into the struct. It will potentially increase the size of the structure by 4 bytes, when you only need one bit. It'd be much more compact to store an array of 'active' bits alongside the array itself. Also, the 'active' bits are probably not useful to the "NPC" (etc) class itself, so it would be best not to accidentally drag them into the cache whenever you operate on an NPC.
Alternatively, you can use a free-list instead of 'active' bits -- alongside the actual data array, you have an array of integers that act as a linked-list (implemented as an array, of course ) of indices of all the elements that aren't active. When allocating an element, you can use the free-list to instantly find an inactive one, as longs as when freeing you return it's index back to this list.
My pool class uses this technique, and it turned out to be faster to allocate from than even my scope/stack allocators (which are ridiculously simple)!
remember OO was invented for people who couldn't write ADT (abstract data type) style non-spaghetti code, and as a slicker way to encapsulate variant records and procedural variables. It has nothing to do with writing games that run fast. May make it easier (for some) to write code, but slower code on average, unfortunately.
code should be C, not C++. No OO, no virtual methods, no mallocs (new, etc), no polymorphism. none of that slow stuff!
C's ADT's are equivalent to interfaces in OOP languages... If you were writing object oriented code in C, you'd likely use ADTs to do so... so the above doesn't really make sense.
OO code does not have to use new excessively, and it doesn't have to use virtual or polymorphism...
Comparing OOP C++ code that's slow because of unnecessary use of dynamic-dispatch and dynamic-allocation, against procedural C code that's well written is not a valid comparison. I can just as easly write slow C code that uses unnecessary dynamic-dispatch (home-made implementation of virtual) and excessive malloc calls, and then compare it against some well-written fast C++ OOP code... but there's no point in such mud slinging.
You're really talking about coding styles, not languages, here.
like most things in game development, there's the easy way and the fast way to do it. if you code each line with clock cycles in mind form the get go, you'll have very little optimization to do at the end.
All the current-gen console games that I've shipped have been mainly written in a slow "scripting" language like Lua. Yeah, thinking about performance is still important, but with Lua, that comes in the form of optimal algorithms and not creating garbage. All that matters is that the game runs within it's budget, which for us was 16ms of time in the Lua VM. That left 17ms of time on the main CPU core (and 33ms on the GPU and other CPU cores) for the engine to use. The engine is C++, and only sacrifices readability/maintainability for performance where necessary -- i.e. unless something is used in a tight loop, it's actually more valuable to the company in the long run for it to be easy to understand and modify over time than that it's as fast as possible, so that multiple games can get out the door in the smallest time-frames.