Skip to main content
GameDev.net gamedev.net
🔒 Locked

(c++) auto-initialize basic variables?

Started by suliman Apr 6, 2010 at 8:11 AM 23 replies 6.2k views
Original Post
suliman
suliman
Hi I add loads of variables like int, bool float to my classes as i go along, and most of the time i need them to start at value 0. But setting this manually in my constuctor is kinda time consuming as i add a lot. Now, i know c++ doesnt auto-init them to 0 (like in java) to optimize but is there any way to override this or otherwise achieve this? I wouldnt mind the small waste of cpu it could be in those cases i need to init it to something other then 0 and it would speed up development. Thanks Erik
Mantear
Mantear
The best way to initialize class member variables is by using the initialization list. It looks like this.
class SomeClass{public:   SomeClass();   int memberInt;   float memberFloat;   SomeOtherClass* memberPtr;};SomeClass::SomeClass(): memberInt(0), // <--- Initialization list  memberFloat(0.0f),   memberPtr(NULL){}


Now, if you have too many members in your class and your initialization list is getting too long, you need to re-think your class design. Break it up into smaller classes and combine them using composition.
suliman
suliman
how is this much different from just init them in the constructor the normal way? I still need to add it at two places for every new int,float etc.

Im asking if there is any way to set it up so i JUST add it in the class, and it's still inited to 0 value.

I understand i can create a class "class myInt, class myFloat" etc that has a default constructor that sets it to 0 but i want something more streamlined. Is it possible in c++?
Ariste
Ariste
I don't know of any way to do what you're asking, but if you find yourself using so many variables in a class that the physical act of typing up the constructor initialization list becomes time consuming, you might want to rethink your design. Is your class really serving a single, focused purpose? If not, consider breaking it up in to smaller classes and combining them in whatever method is appropriate.
Hodgman
Hodgman
If you want to save a few characters you can also write:
SomeClass::SomeClass(): memberInt(), // <--- Initialization list  memberFloat(), // <-- () means zero/NULL  memberPtr(){}


I've always used initialisation lists like above, but if you really want to put the default value in the header, you can write a template class that allows something like:
class SomeClass{public:  Default<int>     m_IntA;//will be initialised to 0  Default<int, 42> m_IntB;//will be initialised to 42}
This is off the top of my head (not tested), but the template would look something like:
template<class T, T init=T()> class Default{public:  Default() : value(init) {}  operator       T&()       { return value; }  operator const T&() const { return value; }  T value;};
Ariste
Ariste
Quote:
Original post by suliman
how is this much different from just init them in the constructor the normal way?


From the standpoint of saving time, it's not much different. The difference is that the initialization list initializes variables while the constructor body assigns to them. The latter is slower because the member variables are initialized to some junk value before being assigned to.
Ariste
Ariste
Quote:
Original post by Hodgman
I've always used initialisation lists like above, but if you really want to put the default value in the header, you can write a template class that allows something like...


That's creative as hell. Neat trick :)
phresnel
phresnel
Slightly off topic, but I have coded an expression templates implementation where I wanted default initialization by default, but also make code like ...

Foo foo; // expression template, initialization is wasteful herefoo = bar + x * y;


.. performant by concept (for some nontrivial cases where initialization is not possible or non-kiss).

I have added an additional ctor-overload so I could write

Foo foo (Foo::noinit); // won't initialize member data


(noinit is declared as member, like enum noinit_{}noinit)

Don't know if such paradigm is common somewhere, but I call it the "no-init paradigm", yay.
Andrew Russell
Andrew Russell
Quote:
Original post by Ariste
Quote:
Original post by suliman
how is this much different from just init them in the constructor the normal way?


From the standpoint of saving time, it's not much different. The difference is that the initialization list initializes variables while the constructor body assigns to them. The latter is slower because the member variables are initialized to some junk value before being assigned to.


Actually (except for debug builds) they aren't initialized to some junk value - they're left as a junk value - a [grin]very[grin] fast operation. The reason that then setting them in the body instead of an initializer list is slower is because the compiler can't simply fill the class with a fast memset operation. Except that it can - it will see you setting things in the body that could be done in the initializer list, and pretend that you did. Of course, this only applies to classes containing POD types.

(Disclaimer: my C++ compiler optimization knowledge is rather rusty.)

Of course, the OP could override new or some other crazy thing to get the desired effect. But please for the love of god do not do this. You simply have to get used to the fact that this is how you program in C++. (If you don't like it, use Java or C#.)

(Story time: My first C++ compiler would always initialize to zero - even in release. This caused me no end of misery, unlearning the bad habit of relying on this feature, when I switched to a better compiler. It also made all my old code unusable. So please don't try it - just learn how to write proper C++ code in the first place.)
SiCrane
SiCrane
Quote:
Original post by Andrew Russell
Story time: My first C++ compiler would always initialize to zero - even in release.


Out of curiosity, which one was this?
phresnel
phresnel
Quote:
Original post by SiCrane
Quote:
Original post by Andrew Russell
Story time: My first C++ compiler would always initialize to zero - even in release.


Out of curiosity, which one was this?


Wasn't it MSVC 6.0 or so?
sheep19
sheep19
You can also do this:

#include <iostream>#include <string>using namespace std;template <class T>class Value{	T val;public:	Value(T v = T()) : val(v){}	operator T() const { return val; }};int main(){	Value <const char *> str = "hey";	cout << str << "\n";	Value <float> flt = 1.01f;	cout << flt;	cin.get();}


It works for built-in types, which is what you want.
Hodgman
Hodgman
Quote:
Original post by phresnel
Wasn't it MSVC 6.0 or so?
I think 6 initialised things to zero in release builds and garbage in debug builds (opposite of what it should do!).
Andrew Russell
Andrew Russell
Quote:
Original post by SiCrane
Quote:
Original post by Andrew Russell
Story time: My first C++ compiler would always initialize to zero - even in release.


Out of curiosity, which one was this?


I believe it was Borland C++ Builder 3.0.
Andrew Russell
Andrew Russell
Quote:
Original post by Hodgman
Quote:
Original post by phresnel
Wasn't it MSVC 6.0 or so?
I think 6 initialised things to zero in release builds and garbage in debug builds (opposite of what it should do!).


Actually - if you assume that 0 is a "safe default" value - then that behavior is reasonable.

In debug you absolutely don't want the compiler setting something "safe" by default - ideally you want it to set it to something unsafe (in Visual C++ it's 0xCDCDCDCD on the heap, for example) so that uninitialized data is more likely to trigger a bug - and to an easy-to-recognise constant, other than zero, so that it's easy to notice in the debugger.

In release builds you could either not touch it (for performance) or set it to zero on the basis that you want to reduce the chances of your release build crashing no matter what - it will make your counters zero, your pointers null, and so on - which is as safe as possible given code with uninitialised value bugs (which is hardly safe at all!).
phresnel
phresnel
Quote:
Original post by sheep19
You can also do this:

*** Source Snippet Removed ***

It works for built-in types, which is what you want.


This was already mentioned as is by Hodgman ;)
Hodgman
Hodgman
Quote:
Original post by phresnel
This was already mentioned as is by Hodgman ;)
Mines untested though, and doesn't support optional initialisation ;)
Quote:
Original post by Andrew Russell
Quote:
Original post by Hodgman
I think 6 initialised things to zero in release builds and garbage in debug builds (opposite of what it should do!).
Actually - if you assume that 0 is a "safe default" value - then that behavior is reasonable.
In debug you absolutely don't want the compiler setting something "safe" by default - ideally you want it to set it to something unsafe (in Visual C++ it's 0xCDCDCDCD on the heap, for example) so that uninitialized data is more likely to trigger a bug - and to an easy-to-recognise constant, other than zero, so that it's easy to notice in the debugger.
Yeah I shouldn't have said 'opposite' (i.e. that debug should be zero and release garbage), that would be bad as you say.

This VC6 behaviour did cause me to have some pointer-bugs that worked in debug but crashed in release though -- VC6 code often actually "worked" (undefined behaviour) if you dereferenced a garbage pointer, but crashed if you dereferenced a NULL pointer, which meant that when it tried to help me by defaulting everything to zero in release, it turned my undefined behaviour into a hard crash! Ahh the joys of being a C/C++ newbie...

I actually ported one of my old "learning" projects from VC6 to VC9 recently, and quickly discovered/fixed a whole bunch of uninitialised pointer bugs in the process, but now the game logic doesn't work the same as it used to because it turns out my code was actually relying on the undefined (but predictable) numbers generated by all my buffer overruns and garbage pointers :/
Arvydas
Arvydas
One dirty trick:
In your class, define something like int _end; as the last parameter, then in constructor: memset(this, 0, int(&_end) - int(this));
Hodgman
Hodgman
Quote:
Original post by A-E
One dirty trick:
In your class, define something like int _end; as the last parameter, then in constructor: memset(this, 0, int(&_end) - int(this));
You could also do: memset(this, 0, sizeof(*this));, but these tricks will do nasty things if this is a non-POD type (e.g. could overwrite your vtable pointer) or if you use inheritance (your base constructor will have executed before the memset executes).
It's pretty dirty... I have seen someone do it at work though (in a professional game), and the consequence was a company-wide email shaming the (thankfully anonymised) author. Use with caution ;D
phresnel
phresnel
Quote:
Original post by Hodgman
Quote:
Original post by phresnel
This was already mentioned as is by Hodgman ;)
Mines untested though, and doesn't support optional initialisation ;)


Mkay :)

One thing I forgot to mention: The default-value in the template-argument-list may only be an integer type and nothing else (no float, no custom types, of course you could make that argument an integer, or pass fractionals or fixed point values).

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.