Sign in to follow this  
ApochPiQ

Initialize your goddamn variables, kiddies

Recommended Posts

I REALLY like compilers that consistently detect when you're about to use a variable that hasn't been initialized. Bonus points if they still manage to compile quickly. Edited by Nypyren

Share this post


Link to post
Share on other sites

I've seen that same demon crush the souls of a dozen gameplay programmers.

We ended up training the CPU to yelp at the smell of the beast:

http://stackoverflow.com/questions/4454582/visual-studio-c-2008-2010-break-on-float-nan

 

There's also the fun cousin of that demon, the denormal numbers, hiding in the infinitesimal gap in between zero and "smallest possible float value". This demon is more insidious - it's poison only slows, instead of killing. On some CPU's these numbers work just fine as floats, except that the CPU drops into a special emulation mode that's a gazillion times slower than normal... So your physics/gameplay code continues to run, and is correct... but is now incredibly slow for some reason!

Edited by Hodgman

Share this post


Link to post
Share on other sites

We always initialized locals pretty aggressively, choosing correctness over performance. Class members, though. Hooooly shit those were the bane of our existence for years. In later C++ versions, the ability to initialize class members in the header has single handedly changed our entire development experience. 

Share this post


Link to post
Share on other sites
If you're looking specifically for an uninitialized structure, you could also make the constructor initialize all the fields to NaN (or some other sentinel) in debug builds, then get the CPU to break on NaNs outside that constructor. Then you could catch the use of the uninitialized structure right as it happens, instead of having to wait for it to get horribly corrupted.

Share this post


Link to post
Share on other sites

If you're looking specifically for an uninitialized structure, you could also make the constructor initialize all the fields to NaN (or some other sentinel) in debug builds, then get the CPU to break on NaNs outside that constructor.


Not quite sure if this is the same thing you mean, but I vastly prefer making the default constructors for all types provide well-defined default values, and then using a "tag constructor" trick for optimized construction in places you know you want to avoid defaults and don't trust the compiler to optimize properly.
 
struct uninitialized_t {};
namespace { const uninitialized_t uninitialized; } // C++98/03
namespace { constexpr uninitialized_t uninitialized; } // C++11/14
constexpr inline uninitialized_t uninitialized; // C++17

template <class T, int M, int N>
struct matrix {
  T m[M][N];

  matrix() { memset(m, 0, sizeof m); }
  matrix(uninitialized_t) { /*do nothing*/ }
};

Just pay attention to code using uninitialized and review it a little more carefully; odds of bugs goes down and old-school programmer happiness goes up. Edited by SeanMiddleditch

Share this post


Link to post
Share on other sites

the fun cousin of that demon, the denormal numbers, hiding in the infinitesimal gap in between zero and "smallest possible float value".

 

Yes, "Fun".

 

When dealing with numbers in games with a 1 meter scale, a good sanity test is: "Is this number less than the width of a hair or fingernail?"  Any distance smaller than around 0.0001 generally ought to become 0.

Share this post


Link to post
Share on other sites

If you're looking specifically for an uninitialized structure, you could also make the constructor initialize all the fields to NaN (or some other sentinel) in debug builds, then get the CPU to break on NaNs outside that constructor.


Not quite sure if this is the same thing you mean, but I vastly prefer making the default constructors for all types provide well-defined default values, and then using a "tag constructor" trick for optimized construction in places you know you want to avoid defaults and don't trust the compiler to optimize properly.


Neat, that's not what I meant but I like that better.

Share this post


Link to post
Share on other sites

There's also the fun cousin of that demon, the denormal numbers, hiding in the infinitesimal gap in between zero and "smallest possible float value". This demon is more insidious - it's poison only slows, instead of killing. On some CPU's these numbers work just fine as floats, except that the CPU drops into a special emulation mode that's a gazillion times slower than normal... So your physics/gameplay code continues to run, and is correct... but is now incredibly slow for some reason!

 

Spent many hours debugging this issue within my audio DSP code. The code for applying an IIR filter unexplainably became about 60x slower, but only when the audio consisted of some signal followed by silence. The output values of the recursive filter would decay toward zero but never reach it. The solution is to enable flush-to-zero for the relevant code.

Share this post


Link to post
Share on other sites

The coding standard was updated, the programmers involved celebrated, and the demon was laid to rest forever.


"Now, three thousand years later, the seal of the tombs are wearing thin, and unbeknownst to our young heroes, the ancient demon was buried under their own little village project."

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this