Of orx, Scroll, C, C++ and Obj-C, OOP and DOD

edited January 2012 in General discussions
This discussion started in the New people! thread and I thought it'd be nicer to continue here instead of completely hi-jacking that thread, so here we go! :)

godexsoft wrote:
Objective-C is definitely not bad. I just prefer compile-time errors to runtime ones ;)

Well I thought the idea was to not get errors at all, actually. After all, nil->message() is allowed. ;)
I also do appreciate stl and the speed difference between std::vector and say NSMutableArray. Last time I measured the difference was about 80-100 times. Can you imagine? :)

Ouch! People have been pestering against the performances of STL implementations for years, so I can't even imagine!
That's why I don't even use dynamic arrays to begin with. ;)
As for Scroll and OO design. I did not say that Scroll is not OO :) What I said is that I prefer modern C++.

Well, I guess that's this notion on which we don't agree. :) I consider things like templated metaprogramming being modern C++, for example, not smart pointers and I feel like what you call modern C++ are actually practices that are not bound to C++ itself.
Take a look at ClanLib's slot system (basically it's some kind of boost::function).

Signals/slots have been introduced by Qt a long time ago and are not C++-specific. At least I wouldn't categorize them as modern C++ as they're not part of the language (as opposed to C# events/delegates, for example). There are even C implementations, although often very ugly.
I also like how they organized configs (xml) and how their resource system works.

Again, I don't think XML has anything to do with C++, modern or not. :) If I'm to trust their API they only propose a DOM approach (I couldn't see any SAX-like serial API) to it too, which is a bit limiting, but that's another issue. Personally I've never liked XML much, and would choose JSON over it, as I find it too verbose and inefficient.

That being said I think ClanLib is a very good library, just not the best example of OO-design nor of C++ use. :)
It's very similar to what I had in my C++ engine (which I only worked on for a couple of months).
Memory management and generally, resource management, with C++ is also much easier. Just remember to do everything the RAII way and you will be fine.

Ah, there I totally agree that C++ contributed to a more simplified and safer memory management approach, especially RAII. They even added RAII extension in GCC for C after that (much better than the Ad-Hoc hacks people came with).
Smart pointers can be emulated in C but it's simply not as elegant.

As for resource management, I'm not sure I quite see your point, unless you speak of the smart pointer approach itself (which isn't specific to resources themselves).
Also, IMHO, there is nothing wrong with passing contexts :)

Well, a context by itself, certainly no.
Unless your context is an object that you pass as argument to a static function. That's reverse OO there. :)
In that respect I think SFML's API, for example, is much cleaner and respectful of OO precepts than ClanLib.
Plain C in my opinion gives everyone including pros the opportunity to screw things up. Especially memory and resources. Take a look at this example:
// inside a function
...
mem = malloc(...);
int ret = operation1();
if(ret != 0) 
{
    free(mem);
    return -1;
}

// How about inserting a 'return' or 'break' ? - here we go.

ret = operation2();
if(ret != 0) 
{
    free(mem);
    return -2;
}

And then of course you can use a 'goto' but that's so dirty..

I totally agree with that, except I think it's more of a beginner issue than an expert one.
On a related topic, I also think one shouldn't have mid-function returns as they're unnatural, and by that I mean they diverge too much from the underlying asm code organization. If it were me, I wouldn't even allow those. :P
I think every allocation/deallocation should follow a strict symmetry.
Now this:
{
shared_ptr<..> mem = shared_ptr<..>( new obj() );
...
if( !operation() )
{
    return;
}
...
}

Well yes, it's safe, but I personally find it ugly because it's breaking an explicit symmetry.

However I admit that shared_ptr<> itself is modern C++ as it comes with C++11, but the underlying reference counting concept is pretty old. ;)
or
{
resource<texture> tr = resource<texture>( "path to resource" );
...
}

The resource will be automatically loaded at construction and unloaded when it goes out of scope unless it was copied by some other function/class to use in say a scene. When the scene is destroyed and the resource is no longer needed the destructor will be called (same as shared_ptr) and the texture will be unloaded from open gl and memory. That's much better, huh? :)

So yes, it's a smart pointer approach but it can be achieve outside C++ as well. Also I don't like the approach of having to hardcode the type via template and I'd rather have it data-driven instead, but that's me. :)

I totally agree that C++ makes the programmer life easier to achieve those approaches but I insist on the fact that the above concepts are not bound to C++ itself and can be made in other languages, even C.

If I didn't like C++ to begin with, I wouldn't have created Scroll myself (and I use it for all my current projects). :)
What I'm saying is that the language itself is dangerous when in the wrong hands.

Let's consider this, for example:
// In your engine/lib/whichever API you use:
class A
{
public:
  int foo() {return 0;}
  int foo(float f) {return 1;}
};

// In your game, you extend it
class B : public A
{
public:
  int foo(double f) {return 2;}
};

// Now can you tell me (without compiling/running ^^) what happens for those calls?
int main()
{
  B b;

  b.foo();
  b.foo(1.0f);
  b.foo(1.0);

  return 0;
}

The issues don't appear to be obvious at first glance, do they? :) And those are language-specific issues.

Or what about calling a virtual method in a c-tor or d-tor?
There are dozen and dozen of dangerous language pitfalls in C++, that's my main gripe with it. And, added to that, a beginner can still make the errors you cited above in C++. :)

Now about OO itself in game development (not in a more general context), there have been very heated debates over the past few years between OOP and DOD. I'm a former asm and still low level coder, so I'll go with DOD as much as possible but will still try to make compromise when I can. :)

Comments

  • edited January 2012
    Well I thought the idea was to not get errors at all, actually. After all, nil->message() is allowed. ;)

    Programmers always introduce bugs and errors. It's generally better to catch them at compile time rather than after hours of testing and debugging. Messages to nil are allowed but that does not mean that your game's logic wont go nuts because of that ;)
    Ouch! People have been pestering against the performances of STL implementations for years, so I can't even imagine!
    That's why I don't even use dynamic arrays to begin with. ;)

    Implementations differ. That's true. However I was testing the default stl which came with gcc and testing that against the default obj-c foundation compiled with gcc. Besides, NSMutableArray does not offer anything good over std::vector. Besides, std::vector is type-safe which might be good or bad depending on your needs.
    Well, I guess that's this notion on which we don't agree. :) I consider things like templated metaprogramming being modern C++, for example, not smart pointers and I feel like what you call modern C++ are actually practices that are not bound to C++ itself.

    Metaprogramming is definitely "modern c++" but I think that, generally, modern c++ is a wider term. I don't think that "modern c++" is only about MP nor do i think that it's a synonym for "all the stuff from the latest standard". I think modern c++ is the way people code in c++ nowadays. RAII all over the place, boost libraries, extensive stl usage, metaprogramming, runloops (asio), memory management using shared pointers and things like boost::enable_shared_from_this, guard locks and all kind of crazy compile-time libraries like boost::spirit.
    Signals/slots have been introduced by Qt a long time ago and are not C++-specific. At least I wouldn't categorize them as modern C++ as they're not part of the language (as opposed to C# events/delegates, for example). There are even C implementations, although often very ugly.

    Yes. Of course it's not C++ specific. But in my opinion boost::function is pure modern C++. I think slots are great and very convenient. I also use boost::function a lot in my projects. Take a look at my blog post to learn how you can build a bridge between C++-based core and Obj-C UI or whatever using boost::function.
    Again, I don't think XML has anything to do with C++, modern or not. :) If I'm to trust their API they only propose a DOM approach (I couldn't see any SAX-like serial API) to it too, which is a bit limiting, but that's another issue. Personally I've never liked XML much, and would choose JSON over it, as I find it too verbose and inefficient.

    I agree. However I think xml wins over ini files because you can control the depth. You could define sections inside sections etc. In my engine I also used xml. In Tapmania I used plists :)
    Well, a context by itself, certainly no.
    Unless your context is an object that you pass as argument to a static function. That's reverse OO there. :)
    In that respect I think SFML's API, for example, is much cleaner and respectful of OO precepts than ClanLib.

    I didn't know they were passing contexts to static functions. That's definitely bad design right there.
    On a related topic, I also think one shouldn't have mid-function returns as they're unnatural, and by that I mean they diverge too much from the underlying asm code organization. If it were me, I wouldn't even allow those. :P
    I think every allocation/deallocation should follow a strict symmetry.

    Every programmer who started to code in C and did that many years ago will tell you the same thing: "mid-function returns are bad, OK?". I disagree. Mid-function returns are great. Along with RAII and the stack the usage of mid-function returns allows to write less code and express your intentions in a explicit way: "I'm done with this function. Get out now".
    Well yes, it's safe, but I personally find it ugly because it's breaking an explicit symmetry.

    However I admit that shared_ptr<> itself is modern C++ as it comes with C++11, but the underlying reference counting concept is pretty old. ;)

    Again, I think "modern c++" stands for a different thing.
    Reference counting is used in many languages including Objective-C's autorelease pool so yes, it's not C++ specific. However, smart pointers only work when you have a stack and guaranteed construction/destruction.
    I don't think it's ugly:
    {
        // in the scope
        shared_ptr<type> t = shared_ptr<type>( new type );
        
        ...
        // t gets deallocated automatically. even on exception or mid-function return.
    }
    

    vs.
    type * mem = new type;
    
    // try returning or throwing an exception here.
    
    delete mem;
    
    So yes, it's a smart pointer approach but it can be achieve outside C++ as well. Also I don't like the approach of having to hardcode the type via template and I'd rather have it data-driven instead, but that's me. :)

    Yes. Data-driven is good. But you always know that your code supports the following types of resources: texture, sound, ...; it's always a predefined set which is known at compile time.
    In my engine I had some MPL craziness which allowed me to do something similar to this:
    #define MAIN_BUNDLE 1
    typedef mpl::vector<png, jpg> graphical_types;
    resource_loader<MAIN_BUNDLE, graphical_types>::load("path to directory");
    // ...
    {
         texture_ptr tp = resource_loader<MAIN_BUNDLE, graphical_types>::get<texture_ptr>("Path::To::Resource::Name");
        // ... use tp ...
        // tp ref counter goes down and tp is unloaded if ref counter is zero
    }
    
    What I'm saying is that the language itself is dangerous when in the wrong hands.

    Any language is ;)
    The issues don't appear to be obvious at first glance, do they? :) And those are language-specific issues.

    It's obvious that you need to specify 'virtual' in the base class if you want to override something.
    Or what about calling a virtual method in a c-tor or d-tor?
    There are dozen and dozen of dangerous language pitfalls in C++, that's my main gripe with it. And, added to that, a beginner can still make the errors you cited above in C++. :)

    Yeah. True.
    You know people say.. It's rather hard to make an error in C++ if you know what you are doing.. but if you make one it will blowup and rip your leg off.
    Now about OO itself in game development (not in a more general context), there have been very heated debates over the past few years between OOP and DOD. I'm a former asm and still low level coder, so I'll go with DOD as much as possible but will still try to make compromise when I can. :)

    Sounds like a good plan! :)
  • edited January 2012
    godexsoft wrote:
    Programmers always introduce bugs and errors. It's generally better to catch them at compile time rather than after hours of testing and debugging. Messages to nil are allowed but that does not mean that your game's logic wont go nuts because of that ;)

    Ahah, yes, that was more a joke than anything else. :)
    Implementations differ. That's true. However I was testing the default stl which came with gcc and testing that against the default obj-c foundation compiled with gcc. Besides, NSMutableArray does not offer anything good over std::vector. Besides, std::vector is type-safe which might be good or bad depending on your needs.

    Are there a lot of people using NSMutableArray out there for their game dev needs? I come from a world where STL and RTTI are considered as bad words.
    Metaprogramming is definitely "modern c++" but I think that, generally, modern c++ is a wider term. I don't think that "modern c++" is only about MP nor do i think that it's a synonym for "all the stuff from the latest standard". I think modern c++ is the way people code in c++ nowadays. RAII all over the place, boost libraries, extensive stl usage, metaprogramming, runloops (asio), memory management using shared pointers and things like boost::enable_shared_from_this, guard locks and all kind of crazy compile-time libraries like boost::spirit.

    I see your point, I think I'm just not comfortable with calling it 'modern C++' as it revolves more about practices and available libraries than language itself but I guess I can live with the term. :)

    Boost is a great library but I've only heard of very few people using it on PS3 for game dev, for example.
    The reasons for that are multiple, ranging from constructor API covered by NDA to not being adapted for running efficiently on a SPU. Most of the time, when people do use it, they're mostly using its containers only.
    Yes. Of course it's not C++ specific. But in my opinion boost::function is pure modern C++. I think slots are great and very convenient. I also use boost::function a lot in my projects. Take a look at my blog post to learn how you can build a bridge between C++-based core and Obj-C UI or whatever using boost::function.

    Slots are very useful for asynchronous I/O or GUI programming, I haven't seen many use in console game engines so far: people tend to avoid them as they're not very code cache friendly.

    Boost::function is great whenever you need the flexibility of a more generalized callback scheme but they also come at a cost.
    I agree. However I think xml wins over ini files because you can control the depth. You could define sections inside sections etc. In my engine I also used xml. In Tapmania I used plists :)

    That's great whenever you need more depth for sure, but I'd still use JSON in that case. ;)
    The good part of ini files, on the other hand, is that its syntax is extremely simple and they're not verbose. :)
    I didn't know they were passing contexts to static functions. That's definitely bad design right there.

    They apparently haven't changed those parts yet, here's an example: http://clanlib.org/docs/clanlib-2.3/reference_doxygen/classCL__Draw.html
    Every programmer who started to code in C and did that many years ago will tell you the same thing: "mid-function returns are bad, OK?". I disagree. Mid-function returns are great. Along with RAII and the stack the usage of mid-function returns allows to write less code and express your intentions in a explicit way: "I'm done with this function. Get out now".

    I strongly disagree with that statement. The important part for me is that my high level code is as close as possible as the underlying compiled representation.
    When compiled, a function has only one entry point and one exit point (excluding setjmp/longjmp hacks).
    When the time comes and you are facing a release-only hard to track bug, it's much more friendly to have your high level code as close as possible as the machine code. The comfort of not having weird duplicated code displayed by the debugger, trying to match the optimized code to the source, or instruction pointers jumping all over the place when stepping, forcing asm debugging, is crucial to me.
    Again, I think "modern c++" stands for a different thing.
    Reference counting is used in many languages including Objective-C's autorelease pool so yes, it's not C++ specific. However, smart pointers only work when you have a stack and guaranteed construction/destruction.
    I don't think it's ugly:
    {
        // in the scope
        shared_ptr<type> t = shared_ptr<type>( new type );
        
        ...
        // t gets deallocated automatically. even on exception or mid-function return.
    }
    

    It's then a matter of taste, I guess. :)
    However I'm not sure why you tie the use of smart pointers to stack only, unless I misinterpreted your sentence: their scope is much wider.

    And again, with flexibility and power comes new caveats that beginners are likely to encounter, such as the performance of shared_ptr in a multithreaded environment (the reference counter is protected against race conditions, which comes at a cost, but keep in mind the pointed data isn't protected!) or cyclic dependencies (and the need to know how to deal with it with weak_ptr, for example).
    type * mem = new type;
    
    // try returning or throwing an exception here.
    
    delete mem;
    

    Returning there would be a bad practice for me. ;)
    But so is the use of a dynamic allocation (still in the context of realtime/game dev, of course, not in a general way), so I assume the new/delete operators have been redefined.
    Yes. Data-driven is good. But you always know that your code supports the following types of resources: texture, sound, ...; it's always a predefined set which is known at compile time.

    Most of the time, yes, but that's not always true, some engines allow hotplug extensions.
    But even if you know the types at compile time, why would you need to explicitly specify it on every allocation request? I think I missed something there.
    Any language is ;)
    To some extent, of course. But C++ adds a whole new world of caveats/traps to those already present in C. :)
    It's obvious that you need to specify 'virtual' in the base class if you want to override something.

    Well, then it's even less obvious than I thought! ;)

    It's not a problem of virtuality at all, I wasn't trying to override anything.
    Even worse: if you set all methods in A to be virtual, nothing will change and you'll still get the exact same result/problem.

    The underlying problem here is how C++ does scope resolution when trying to find the right method to use.
    If you try the code, the first call won't compile at all.
    The next two will yield a result of 2. Interesting, isn't it? ;)
    It comes from the fact C++ will use the naked method (not the mangled one!) name to find the scope, and it'll find foo in B. Having determined that B is the right scope, it'll then try to find the best candidate there, and in our case there's only one.
    Yeah. True.
    You know people say.. It's rather hard to make an error in C++ if you know what you are doing.. but if you make one it will blowup and rip your leg off.

    I wholeheartedly agree with the second part of the statement but I still think it's very easy to make an error in C++, especially on large scale projects with a lot of contributors with different levels of expertise. ;)
    Now about OO itself in game development (not in a more general context), there have been very heated debates over the past few years between OOP and DOD. I'm a former asm and still low level coder, so I'll go with DOD as much as possible but will still try to make compromise when I can. :)

    Sounds like a good plan! :)

    Thanks! :)

    Also, to clarify a few things, I'm not saying that all the "modern C++" features are bad at all, far from it actually.
    It's just that some of them don't apply to certain specific areas of low level game development, especially for some architectures/consoles. For example, the lack of branch prediction on PS3 or the DMA transfers for SPUs will force you to write your code in a much different way than on PC. That also make the reuse of generic utility C++ libraries harder in that case.

    Another example: smart pointers aren't exactly useful when you have almost no real dynamic allocations, aren't they? That's what happens in most console game engines.
    In orx, for performance sake, there aren't many dynamic allocations going on, even when *_Create*() functions are called.
    That allows us to minimize memory fragmentation, be as cache friendly as possible with increased memory locality and respect alignment requirements while still giving most of the dynamic aspects the user would expect.
  • edited January 2012
    Hi, I'm actually a "beginner", maybe a little further but not too much. So I don't fully understand your discussion. But still wanna join. Correct me if I'm wrong, thanks.
    Ouch! People have been pestering against the performances of STL implementations for years, so I can't even imagine!

    OK I think this is surely true. Libs are never perfect. But I still think STL is good, at least for non-experts. Non-memory-leak makes debugging faster. And STL is fast enough in most of the situations. This is one of reasons that OO rocks, agian for non-C-experts. At least OO makes coding easier and therefore people can make more complex games. Make it fast enough and focus on making it as good as possible is how companies survive, I will say.
    For example, the lack of branch prediction on PS3 or the DMA transfers for SPUs will force you to write your code in a much different way than on PC. That also make the reuse of generic utility C++ libraries harder in that case.

    This is interesting to know PS3 CPU is not good at predictions. So in this case I totally agree lower level coding is better.
    Something else below

    I actually have been looking around for game engines for my indie plan. I found Java ones, scripts ones, XNA and some C/C++ ones. I tried a Java engine and didn't like its performance at all. So I didn't even look into script ones. I'm happy to find orx and like it a lot, before I found it's driven by ini mixed with C. At first I thought it's kind of scripting, but later I find that I can make the configs only loaded at "loading time". The particle system and physical rocks too. The only doubt for me is, configs looks like kind of OO for game objects. However it is not convenient to create complex "methods", in OO term, in inis. This makes object operations happens in two places, inis and C. And I see tricks here and there, like "dummy objects to hold these, those", which are not straight forward. I'm not here to challenge orx. I'm trying to get a better understanding and hopefully stick to it.
  • edited January 2012
    StAkira wrote:
    Hi, I'm actually a "beginner", maybe a little further but not too much. So I don't fully understand your discussion. But still wanna join. Correct me if I'm wrong, thanks.

    I'm glad you joined the discussion, StAkira, the more, the merrier! And it's even better as you're bringing a more "beginner" point of view. :)
    OK I think this is surely true. Libs are never perfect. But I still think STL is good, at least for non-experts. Non-memory-leak makes debugging faster. And STL is fast enough in most of the situations. This is one of reasons that OO rocks, agian for non-C-experts. At least OO makes coding easier and therefore people can make more complex games. Make it fast enough and as good as possible is how companies survive, I will say.

    I completely agree. STL and Boost are great libraries, especially for beginners. My objections only apply in the very specific and tiny domain that is low level game/engine programming. :)
    I too think that OO is a great way of designing complex architectures.
    This is interesting to know PS3 CPU is not good at predictions. So in this case I totally agree lower level coding is better.
    PS3 is an annoying beast to tame, at least it is at first. Its whole architecture is unusual, writing SPU code requires some unusual knowledge (they don't have access to the main memory, hence the need for DMA transfers, they only have 256KiB of memory shared between the code and the data and they have 128 128-bits registers).
    I actually have been looking around for game engines for my indie plan. I found Java ones, scripts ones, XNA and some C/C++ ones. I tried a Java engine and didn't like its performance at all. So I didn't even look into script ones. I'm happy to find orx and like it a lot, before I found it's driven by ini mixed with C. At first I thought it's kind of scripting, but later I find that I can make the configs only loaded at "loading time". The particle system and physical rocks too. The only doubt for me is, configs looks like kind of OO for game objects. However it is not convenient to create complex "methods", in OO term, in inis. This makes object operations happens in two places, inis and C. And I see tricks here and there, like "dummy objects to hold these, those", which are not straight forward. I'm not here to challenge orx. I'm trying to get a better understanding and hopefully stick to it.

    I'm glad you like orx so far and I hope it'll continue to grow on you. :)
    You're right about the config system: orx was supposed to offer scripting support (especially interesting for accessing hot-loaded extensions, a system that orx supports since the beginning), via a plugin. However the coder who started it never had the opportunity to finish it before leaving the project.
    The config system appeared much later and has been a bit abused to emulate near-scripting capacities in certain cases. It's definitely not a scripting replacement and was never intended to be so.
    However, when it allows to create a whole scene, modify object setups on the fly or provide easy creation, why not using it to its full extent. It sometimes looks hacky for sure, but I think those tricks are useful for simplifying the dev's life (because that's the end goal, isn't it?) as long as we don't have a real scripting support. :)

    Even the particle system isn't really one, it's an object spawner system that was meant for projectiles/enemies management, but in the end, coupled with the config system (and the physics one), it makes a pretty decent particle system, as you said. :)

    As for using dummy empty objects, objects are meant to be used as containers, and as such they provide a nice uniform wrapper to access most of the properties that can be attached to them (like having a music object, a scene parent, a camera object, etc.). This part isn't actually linked to the config system itself and was meant to be generic this way since the beginning.
  • edited January 2012
    Are there a lot of people using NSMutableArray out there for their game dev needs? I come from a world where STL and RTTI are considered as bad words.

    Well, to be honest, I use that in Tapmania :)
    std::vector on the other hand is almost always better than custom arrays and stuff like that.
    I strongly disagree with that statement. The important part for me is that my high level code is as close as possible as the underlying compiled representation.
    When compiled, a function has only one entry point and one exit point (excluding setjmp/longjmp hacks).
    When the time comes and you are facing a release-only hard to track bug, it's much more friendly to have your high level code as close as possible as the machine code. The comfort of not having weird duplicated code displayed by the debugger, trying to match the optimized code to the source, or instruction pointers jumping all over the place when stepping, forcing asm debugging, is crucial to me.

    I can't agree. Generating good asm code is a task for the compiler, not for the programmer. Perhaps there is a big difference when you are developing games for console platforms.. I found it very convenient to use modern c++ along with lots of libraries on iPhone/Android development.. even in game development for non-console platforms.

    Well, then it's even less obvious than I thought!

    It's not a problem of virtuality at all, I wasn't trying to override anything.
    Even worse: if you set all methods in A to be virtual, nothing will change and you'll still get the exact same result/problem.

    Of course. I didn't look carefully and missed the point. Yes, there is a bug in c++03 which, afaik, is fixed in c++11. The behaviour you describe is just bad design of c++03. But you may agree, that it's unlikely you will have a setup like this anyway. I mean i can't think of a scenario where you would have this kind of member functions along with inheritance.
    Thanks!

    Also, to clarify a few things, I'm not saying that all the "modern C++" features are bad at all, far from it actually.
    It's just that some of them don't apply to certain specific areas of low level game development, especially for some architectures/consoles. For example, the lack of branch prediction on PS3 or the DMA transfers for SPUs will force you to write your code in a much different way than on PC. That also make the reuse of generic utility C++ libraries harder in that case.

    Another example: smart pointers aren't exactly useful when you have almost no real dynamic allocations, aren't they? That's what happens in most console game engines.
    In orx, for performance sake, there aren't many dynamic allocations going on, even when *_Create*() functions are called.
    That allows us to minimize memory fragmentation, be as cache friendly as possible with increased memory locality and respect alignment requirements while still giving most of the dynamic aspects the user would expect.

    I have zero experience on console platforms so I will just trust your experience here :)

    Smart pointers, however, are used in a much wider scope than just memory allocation. My example resource template can also be called a smart pointer because it's basically based on the same concept.

    I agree that heap usage must be minimised as much as possible. But you will agree that allocations are nothing bad unless you allocate/release hundreds of objects at 60hz :)
    I mean there is nothing wrong with allocating a lot of stuff once and then just use it. For example you will have to load a "map" into memory. You will have to load your resources and textures are definitely big enough to go onto the heap while you process them.

    That being said, in c/c++ we have the stack and primitive types or even structures and classes which we can use without heap allocations.
    For example in Java you can't make a "point struct" and have an array of active points/vertices on the stack. You are forced to use a class which will always end up on the heap.
    Then, to be efficient in Java, your only choice is having two static arrays of floats/ints, one for X values and one for Y values. Only that way they wont be dynamically allocated.
  • edited January 2012
    godexsoft wrote:
    Well, to be honest, I use that in Tapmania :)

    I guess that was before doing the performance test, then? ;)
    std::vector on the other hand is almost always better than custom arrays and stuff like that.

    I don't agree. In my experience, it's actually quite the contrary, at least when it comes to the default STL implementations that ship with compilers.
    The link I posted earlier gives a good breakdown of common issues that come with default implementations.
    Now I haven't checked C++11 in that matter, and it's possible they might have been fixed.
    I can't agree. Generating good asm code is a task for the compiler, not for the programmer.

    That wasn't my point, actually. My point is that the more you diverge from the underlying workflow, the more it gets harder to debug a release build from the source.

    However, you actually raise an interesting point. Game console CPUs have historically a lot more constraints than regular PCs (or ARM CPUs, in that respect). They're getting better but it's not uncommon to not have branch prediction or out-of-order execution, for example, and you have to take those in account when writing your code.
    Perhaps there is a big difference when you are developing games for console platforms.. I found it very convenient to use modern c++ along with lots of libraries on iPhone/Android development.. even in game development for non-console platforms.

    I'm all with you about the convenience. It's just not the highest priority in all domains and performance tend to be the top one on console game engines.
    And even for convenience, STL is lacking some precious features like intrusive containers.
    Of course. I didn't look carefully and missed the point. Yes, there is a bug in c++03 which, afaik, is fixed in c++11. The behaviour you describe is just bad design of c++03. But you may agree, that it's unlikely you will have a setup like this anyway. I mean i can't think of a scenario where you would have this kind of member functions along with inheritance.

    Afaik it was there before C++03 but I'm glad to learn that they addressed this issue in C++11. And about the likeliness, that was the first example that came to mind because I stumbled upon one case of it last November, in a much more complex situation, of course. :)

    Same for the virtual methods called in c-tor/d-tor. It was done in a 3rd party library we were using and we didn't have access to its source. I ended up using my favorite hex editor to directly patch the library binaries.
    I have zero experience on console platforms so I will just trust your experience here :)

    Well, it's getting better with recent architectures, but there are still a lot of constraints to take into account when writing low level code. :)
    Smart pointers, however, are used in a much wider scope than just memory allocation. My example resource template can also be called a smart pointer because it's basically based on the same concept.

    Ah I see what you mean, I took the term too literally, I guess. :)
    I agree that heap usage must be minimised as much as possible. But you will agree that allocations are nothing bad unless you allocate/release hundreds of objects at 60hz :)

    Well, even if you don't do it that often and performance aside, you'll still end up with the memory fragmentation issue as I assume all your allocations are not the same size over your entire game. :)
    I mean there is nothing wrong with allocating a lot of stuff once and then just use it. For example you will have to load a "map" into memory. You will have to load your resources and textures are definitely big enough to go onto the heap while you process them.

    I agree!
    Though it depends on how many resources you have to track and what your load times are. How it's done in most of the games and engines on/with which I've worked (not including games that support streaming) is that resources are pre-processed offline to match the actual architecture (including endianness and data organization, like pushing actual data on the outer part of the disc to benefit from higher transfer rates) and are then loaded in a single pass in memory + pointers fixup.
    That's an interesting strategy only if you have 10 000s or 100 000s assets to load for your level though, not really adapted for small to medium sized games.
    That being said, in c/c++ we have the stack and primitive types or even structures and classes which we can use without heap allocations.
    For example in Java you can't make a "point struct" and have an array of active points/vertices on the stack. You are forced to use a class which will always end up on the heap.
    Then, to be efficient in Java, your only choice is having two static arrays of floats/ints, one for X values and one for Y values. Only that way they wont be dynamically allocated.

    Eek, it's been so long since I wrote some Java code (13+ years) that I didn't even remember that. I never wrote any game in Java though. :)
Sign In or Register to comment.