Why must a variable be initialized ?

Started by
49 comments, last by Aardvajk 12 years, 10 months ago

@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.


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 name='Aardvajk' timestamp='1308643129' post='4825873']
I'm going to go out on a limb here and argue that for, say, an int, there is no such thing as an insane value. 0 is no more a default value than 325434 or -26. On this basis, I don't see any advantage to initialising an int to 0 unless that happens to be the value I intend it to hold for other reasons.


@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.


0 also IS the default value for POD types. :-p
[/quote]

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.
Advertisement

I generally agree with ApochPiQ, except I am happy to have code like this:
int x;
std::cin >> x;


I would much rather not give x a value that will never be used. Notice that I declare x as late as possible, so it's trivial to verify that it will always be assigned a value.


If your going to do that, then I would suggest something like this:

int x = get<int>();


where get<int>() should be a template function that has proper error handling and all that extra stuff
Edge cases will show your design flaws in your code!
Visit my site
Visit my FaceBook
Visit my github
Code like reading from std::cin is an example of where "uninitialised" warnings tend to fail.

#include <iostream>
#include <sstream>
#include <string>

void test(const std::string &str) {
std::stringstream stream(str);
int i;
if(stream >> i) {
std::cout << "Success: " << i << '\n';
} else {
std::cout << "Failure: " << i << '\n';
}
}

int main() {
test("42");
test("Hello");
}

GCC doesn't warn that "i" is uninitialised in the "else" branch. It obviously assumes that if you pass a reference or pointer to an uninitialised variable to a function, when it returns the variable has been initialised. Usually true, but not always.

Something like D.Chhetri 's code is preferable, we can throw an exception from get(), ensure the variable is correctly initialised or never used.

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.

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.

I'm going to go out on a limb here and argue that for, say, an int, there is no such thing as an insane value. 0 is no more a default value than 325434 or -26. On this basis, I don't see any advantage to initialising an int to 0 unless that happens to be the value I intend it to hold for other reasons.


The point isn't that int has an inherent invariant that's being preserved by initialization; the point is that your code's interpretation 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.

Even in highly contrived demonstration programs, having a known reliable initial value is preferable to a totally unpredictable, undefined value.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


[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.

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.
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.

The point isn't that int has an inherent invariant that's being preserved by initialization; the point is that your code's interpretation 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.

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.


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.

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
Wow, ohmy.gif. This is allot of information from different perspectives , thanks to everyone for explaining the topic. :D
Also very important for pointers. If you're not initializing your pointers, you will someday have trouble. If you're lucky it will just crash right away, but it could 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.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement