• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
vaironl

Why must a variable be initialized ?

50 posts in this topic

[quote name='way2lazy2care' timestamp='1308668957' post='4826014']
[quote name='Aardvajk' timestamp='1308667873' post='4826004']
Only for globals and statics where there is no overhead in having such an initialisation. There is no such thing as a "default" value for a stack-based POD.
[/quote]
Sure there is, it's just that the default value isn't assigned until initialization. If you default initialize a POD type, the value you get is 0

edit: and to further what you said in the same post but above the reply to me. Debug builds do all sorts of weird things specifically with variable initialization vs final builds. I'm pretty sure the debugger I use at work default initializes everything that isn't explicitly initialized and does a lot of attempts at mimicking compiler optimizations that are not what the final build does.

Not to say that behavior is bad, but just to back up your assertion that debug builds are not necessarily the best indicators of what is actually happening in this instance.
[/quote]

True enough, and for the record I have no idea why your post got four rate downs - I actually rated it up.

I admit I'm arguing a pretty silly point here really.
0

Share this post


Link to post
Share on other sites
The C++ standard has a wonderfully confusing set of definitions that often are at ninety degrees with common sense. Section 8.5 of the current version contains all the details, but when POD types are "default initialized" that initialization is as if they had been initialized with 0's. On the other hand, "default initialization" only happens in a limited set of occasions, so "default initialization" doesn't happen by default most of the time. Most of the time when a POD variable lacks an initializer it is uninitialized rather than "default initialized" and thus has an indeterminate value.

IIRC, this particular confusion was the result of templates being added to the language and the desire for the expression T() to have a reliable meaning for when T is a POD type. Before that, C++ avoided the confusing term of default initialization and only had zero initialization and uninitialized values. I don't care enough to fact check this paragraph, however.
1

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1308671460' post='4826028']
The point isn't that int has an inherent invariant that's being preserved by initialization; the point is that your code's [i]interpretation[/i] of that int has invariants. Are you using the int to represent a counter? Initialize to 0. Are you using the int to represent a multiplicative accumulator? Initialize to 1. Are you using the int to represent the answer to life, the universe, and everything? Initialize to 42.

Outside of highly contrived demonstration programs, every variable has a purpose, and that purpose comes with baggage: namely, assumptions about what values "make sense" and where the value should start off.
[/quote]
I actually initialize a lot of numbers to -1 because it's usually a good error condition that's pretty easy to check against when I'm not using them as counters. Though I could see 0 being similar as then you could use it without having to do a comparison. Not sure how good a practice that is though. I haven't really thought about it enough to make a good technical argument for doing it that way.

[quote name='Aardvajk' timestamp='1308673717' post='4826043']
True enough, and for the record I have no idea why your post got four rate downs - I actually rated it up.

I admit I'm arguing a pretty silly point here really.
[/quote]
I'm guessing it's related to the argument being about default values without initialization and I could be interpreted as saying that it does have one of those, even though it is not what I said/meant :-p
0

Share this post


Link to post
Share on other sites
Wow, [img]http://public.gamedev.net/public/style_emoticons/default/ohmy.gif[/img]. This is allot of information from different perspectives , thanks to everyone for explaining the topic. :D
1

Share this post


Link to post
Share on other sites
Also [i]very [/i]important for pointers. If you're not initializing your pointers, you [i]will[/i] someday have trouble. If you're [i]lucky[/i] it will just crash right away, but it [i]could[/i] also pick up stack garbage that converts to a pointer to something that seems valid and that runs just fine for a while, but eventually crashes or exhibits weird behaviour in a totally unrelated part of your code.
1

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1308671460' post='4826028']
The point isn't that int has an inherent invariant that's being preserved by initialization; the point is that your code's [i]interpretation[/i] of that int has invariants. Are you using the int to represent a counter? Initialize to 0. Are you using the int to represent a multiplicative accumulator? Initialize to 1. Are you using the int to represent the answer to life, the universe, and everything? Initialize to 42.
[/quote]

I agree with you.

For those who doesn't agree; It's just about choosing logical numbers when you initilize. For example, if I have a timer that counts down from 60 seconds, wouldn't the most logical initialization number be 60 then?

When we are talking about initialization, I just have to put in a small question. When programming in C# XNA, how would you initialize your variables?
1. When you declare them
2. In the constructor
3. In the Initialize method

All three ways works. So far I've always initilized in the constructor as some classes recives parameters. Which one is the "more" correct?
0

Share this post


Link to post
Share on other sites
[quote name='falcon93' timestamp='1308680959' post='4826087']
When we are talking about initialization, I just have to put in a small question. When programming in C# XNA, how would you initialize your variables?
1. When you declare them
2. In the constructor
3. In the Initialize method

All three ways works. So far I've always initilized in the constructor as some classes recives parameters. Which one is the "more" correct?
[/quote]

well C# is kind of different. C# default initializes every member variable to 0 or null if they are a value type or reference type respectively. Personally I would do it in the constructor for 99% of the cases. If you are going to fill it with a meaningful value in the initialize function vs constructor (if they have to be different), I would still give it some default value in the constructor.

One time I might not is if I am perhaps storing some sort of cache or something whose point of existing is that something shouldn't be stored in it all the time. This sentence sounded horrible in my head and I'm not quite sure how to say it better, so I am just going to stop. C# is managed and usually throws useful errors, so I find myself slightly less willing to learn the ins and outs perfectly.
1

Share this post


Link to post
Share on other sites
Class members in C# [b]are[/b] default initialized, so it's recommended that you don't do additional initialization on top of them unless you're going to be setting them to a different value than the default. Locals, on the other hand, require that you initialize them before first use, and the compiler will give you an error if you don't.
2

Share this post


Link to post
Share on other sites
We are arguing apples and oranges here. If there is a logical initial value for a variable, then nobody is arguing that it shouldn't be initialised. The debate as I understood it was whether you should initialise a local POD if you are going to then overwrite that value with another one prior to first-read.

I actually agree with iMalc's comment on the last page - I've been struggling to think of an example of an instance where you actually need to declare a variable prior to knowing what it needs to contain, apart from the idiomatic std::cin example. In that example, given that you would be checking the fail state of the stream rather than the contents of the variable for an error, I still maintain that there is little point giving an int a "default" value prior to the read. If you are incorrectly assuming the variable contains a valid value, the error is not checking the stream for a fail, not not default initialising the variable.

But of course it is irrelevant with a modern compiler, so I'll still probably sleep okay tonight. :)
0

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1308695585' post='4826173']
Resource acquisition[b] is [/b]initialization. This is a deep mantra of C++ and should be taken to heart.

If you don't need a resource yet (POD variable, in this case) don't define it. If you do need it, initialize it. Period.


Nobody's saying you should initialize and then overwrite and then read; I'm saying you should initialize with preference to assigning over top of an uninitialized value. This has serious implications for non-POD types so doing it for all types is a good habit. I disagree fundamentally with the std::cin example for reasons I already provided, as well as the fact that a "real" system should be wrapping error checking for potential stream failures into a template function or something, as someone else already indicated as well.

In short, in properly written code, the initialize-write-read situation [i]should never occur in the first place[/i]. You either have initialize-read, or you don't define the variable/object at all.
[/quote]

I totally agree with this right here. This is the one thing that every programmer should take to heart. When I code I create the variable when I need it I don't declare/initialize it before that moment. This is actually one of the biggest advantages C++ has over C. In C prior to C99 I believe correct me if I am wrong but you MUST declare all your variables at the top of a function before code. With C++ and C99 you can declare your variables anywhere.

A majority of the time when I declare my variables it is when I need it and it is receiving a variable from somewhere that it should have. You see this in for loops when you use for(int i = 0; i <= 20; i++) or even more often the variable receives something from a function int i = add(3, 5); If you sit down and look at proper C++ usually this is how it is done period. If you don't need a variable at that exact moment why waste memory leaving it lay around till later.
0

Share this post


Link to post
Share on other sites
Well I can think of a few examples. For example, what if the initialization code is conditional, but you need access to the variable in the enclosing scope?

[code]int f;

switch (x)
{
case 0: f = someval; break;
case 1: f = someotherval; break;
default: f = somethirdval; break;
}

//value of f used here[/code]
0

Share this post


Link to post
Share on other sites
[quote name='Storyyeller' timestamp='1308700563' post='4826202']
Well I can think of a few examples. For example, what if the initialization code is conditional, but you need access to the variable in the enclosing scope?

[code]int f;

switch (x)
{
case 0: f = someval; break;
case 1: f = someotherval; break;
default: f = somethirdval; break;
}

//value of f used here[/code]
[/quote]

This is the kind of code where the new lambda support in C++0x can come into play:

[code]
int f = [&x]() -> int
{
switch (x)
{
case 0: return someval;
case 1: return someotherval;
default: return somethirdval;
}
}();
[/code]

You get the best of both worlds. You can even declare f const if you want.
1

Share this post


Link to post
Share on other sites
Well I'm using GCC 4.4.1, which unfortunately doesn't support lambdas.
0

Share this post


Link to post
What if the switch statement calculates multiple values?
I guess you could create a special struct and make a function that returns it, but that is starting to get unnecessarily complicated.

Also, what if you're stuck with an older compiler that doens't have full C++0x support?
0

Share this post


Link to post
Share on other sites
[quote name='Storyyeller' timestamp='1308709975' post='4826234']
What if the switch statement calculates multiple values?
I guess you could create a special struct and make a function that returns it, but that is starting to get unnecessarily complicated.
[/quote]

It is just syntactic sugar. It allows you to define a local function that returns the desired value to assign at declaration. It can return anything a regular function can, like a struct or a tuple. The lambdas allow you to put the value generation code along with the definition.

[quote]
Also, what if you're stuck with an older compiler that doens't have full C++0x support?
[/quote]

As mentioned before, lambdas are just syntactic sugar, allowing the use of local functions. You could replace the lambda with a function defined else where. The lambda can just make it eaiser to see what is going to get assigned. You could also look into using boost-lambdas.
1

Share this post


Link to post
Share on other sites
[quote name='Storyyeller' timestamp='1308700563' post='4826202']
Well I can think of a few examples. For example, what if the initialization code is conditional, but you need access to the variable in the enclosing scope?

[code]int f;

switch (x)
{
case 0: f = someval; break;
case 1: f = someotherval; break;
default: f = somethirdval; break;
}

//value of f used here[/code]
[/quote]

This is all well and good if you are the only person working on the code, but that is rarely the case. What happens when some dumb guy throws in a third case that doesn't set f? What happens 3 years down the line when there are 100 lines of code between the switch and where f gets used? What happens when the function gets split up or parts of it get commented out? What happens if all of these things happen?

A lot of good programming practice can be thrown out the window when you are working with 1-3 programmers. Once you have people fidgeting with the whole codebase frequently, these tiny things become important.

DISCLAIMER: I have definitely not been super diligent on RAII in the past, and it does become a pain.
1

Share this post


Link to post
Share on other sites
Factor the switch into a function, and then int x = foo(); and you're done.

If that's not a reasonable option, then:

[code]int x = default_value;
switch(foo)
{
case 1: x = 42; break;
case 2: x = 666; break;
}[/code]

Done.


No need to delay initialization, ever [img]http://public.gamedev.net/public/style_emoticons/default/smile.gif[/img]
0

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1308695585' post='4826173']
I disagree fundamentally with the std::cin example for reasons I already provided, as well as the fact that a "real" system should be wrapping error checking for potential stream failures into a template function or something, as someone else already indicated as well.[/quote]

I don't mean to nitpick, but surely this just moves the relevant code into the template function?

[code]
template<class T> T get(std::istream &is)
{
T t; // are we saying this should be T t=T(); ?
is >> t;

if(is.fail()) throw error();

return t;
}
[/code]

Or

[code]
template<class T> bool get(std::istream &is,T &t)
{
is >> t;
return !is.fail();
}

void f()
{
int i; // should this be int i=0; ?
while(!get(std::cin,i)) std::cout << "Value is invalid\n";

std::cout << "You entered " << i << "\n";
}
[/code]
0

Share this post


Link to post
Share on other sites
[quote]
I don't mean to nitpick, but surely this just moves the relevant code into the template function?
[/quote]
Well, at least you've minimised the scope of the problem now to a trivial one.

I'm not militant about this, for reading from standard streams I generally just leave the variable uninitialised and try my best not to trip up. While I have written such template wrappers before, I don't always use them. Practicality before perfection sometimes.

[quote]
This is all well and good if you are the only person working on the code, but that is rarely the case. What happens when some dumb guy throws in a third case that doesn't set f? What happens 3 years down the line when there are 100 lines of code between the switch and where f gets used? What happens when the function gets split up or parts of it get commented out? What happens if all of these things happen?
[/quote]
One of the best things about moving the conditional "initialisation" to a separate function is that you can let the compiler warn you about or prevent control paths that don't return a value.

At work we have some people who like to conditionally "initialise" variables and I always move to a function call when I'm editing such a file.
0

Share this post


Link to post
Share on other sites
Just a small question here, can switch contain a default option? [img]http://public.gamedev.net/public/style_emoticons/default/ohmy.gif[/img] Like this?

[code]
switch (x)
{
case 1: y = 5; break;
case 2: y = 10; break;
default: y = 0; break;
}
[/code]


Is this possible? If yes, then I've learned something new today [img]http://public.gamedev.net/public/style_emoticons/default/smile.gif[/img]
0

Share this post


Link to post
Share on other sites
I'd write the function thusly:

[code]template <typename T> GetFromStream(std::istream& stream)
{
T value;
if(!(stream >> value))
throw std::exception("Failed to read from stream");

return value;
}

// elsewhere
int foo = GetFromStream<int>(std::cin);[/code]

This contains the initialization of the T resource to what amounts to a constructor that can be used for primitive types. The bonus here is that you get semantics exactly like those of constructing a non-primitive type, namely that if construction fails, we get an exception. Yes, strictly speaking, I don't initialize T with T() in the template function - but it is trivial to verify that it behaves correctly with a cursory read-through, [i]and you only have to do that verification once anywhere in your program assuming you are disciplined in using the wrapper[/i].

It's all about containing unexpected situations and propagating expected semantics outwards from those containment points - principle of least surprise, and all that.
0

Share this post


Link to post
Share on other sites
A simple explanation for new coder...

When you write int a; You aren't actually creating anything. You are telling the compiler that you need an address with sizeof(int) bytes to store a value. The program just finds a valid address, and then your variable is just an alias to it. Whatever the bits were set to at that memory address will form the contents of your variable.

If you don't give your variables proper initialization values, you will end up accidentally reading from them and having catastrophic bugs. You may end up writing out gigs of data to someone's hard drive when you meant to only write out a few kilobytes, because you assigned a value in the middle of some flow control statements and conditionals, and none of them ever executed. You may have a for-loop that never ends because you are going to iterate through it several billion times.

C and C++ are systems level programming languages.

Because of this, they usually shouldn't do anything for you behind your back. In some situations, auto variable initialization would be a very bad thing to do. A driver or service may need to grab some memory addresses used by other processes, or as hardware buffers, and zeroing them out could cause all kinds of bugs.

Also, it would be very wasteful, especially on slow embedded platforms to auto-initialize large arrays, only for the next few lines of code to be a big for loop that initializes it all to the proper values. This may cause a huge delay.
1

Share this post


Link to post
Share on other sites
[quote name='Daaark' timestamp='1308733607' post='4826351']
A simple explanation for new coder...

When you write int a; You aren't actually creating anything. You are telling the compiler that you need an address with sizeof(int) bytes to store a value. The program just finds a valid address, and then your variable is just an alias to it. Whatever the bits were set to at that memory address will form the contents of your variable.

If you don't give your variables proper initialization values, you will end up accidentally reading from them and having catastrophic bugs. You may end up writing out gigs of data to someone's hard drive when you meant to only write out a few kilobytes, because you assigned a value in the middle of some flow control statements and conditionals, and none of them ever executed. You may have a for-loop that never ends because you are going to iterate through it several billion times.

C and C++ are systems level programming languages.

Because of this, they usually shouldn't do anything for you behind your back. In some situations, auto variable initialization would be a very bad thing to do. A driver or service may need to grab some memory addresses used by other processes, or as hardware buffers, and zeroing them out could cause all kinds of bugs.

Also, it would be very wasteful, especially on slow embedded platforms to auto-initialize large arrays, only for the next few lines of code to be a big for loop that initializes it all to the proper values. This may cause a huge delay.
[/quote]

Ok, so let me see if I get the bit, "Because of this, they usually shouldn't do anything for you behind your back. In some situations, auto variable initialization would be a very bad thing to do. A driver or service may need to grab some memory addresses used by other processes, or as hardware buffers, and zeroing them out could cause all kinds of bugs.
" How would I know when these drivers/servers need to grab the memory? or in what kind of situation?


so for loops ' Initialize variables'
0

Share this post


Link to post
Share on other sites
[quote name='Aardvajk' timestamp='1308667873' post='4826004']
[quote name='JackTheRapper' timestamp='1308645313' post='4825878']
@Aardvajk: initialising to 0 is predictable, consistent and testable. It will also screw up equations in a consistent way that is easily detectable with a debugger. Random values arent and can do all sorts of insidious things like cause integers to inoccuously roll over and just generally spoil the party. At least, that's my interpretation of the situation.
[/quote]

It would be feasible I guess for a compiler to initialise a local POD variable to zero in debug build if this was desired. Behaviour desired for debugging should be removable by switching build types, not by modifying code.[/quote]But predictability and consistency is still useful for release builds - and in particular, it's desirable for release builds to have the same behaviour as debug builds. Unless you like having bugs that only show up in release builds.
0

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  
Followers 0