It’s pretty nice to catch some really obvious errors when using unset local variables or when accessing a class or struct’s members directly prior to initializing them. In visual studio 2008 you get an “uninitialized local variable used” warning at compile-time and get a run-time check failure at the point of access when debugging.
However, if you access an uninitialized struct’s member variable through one of its functions, you don’t get any warnings or assertions. Obviously the easiest solution is don’t do that, but nobody’s perfect.
For example:
struct Test
{
float GetMember() const { return member; }
float member;
};
Test test;
float f1 = test.member; // Raises warning, asserts in VS debugger at runtime
float f2 = test.GetMember(); // No problem, just keeps on going
This surprised me, but it makes some sense — the compiler can’t assume calling a function on an unused struct is an error, or how else would you initialize or construct it? And anything fancier just quickly brings up so many other complications that it makes sense that it wouldn’t bother classifying which functions are ok to call and when, especially just as a debugging help. I know I can set up my own assertions or error checking within the class itself, but that can complicate some simpler structs.
Still, it would seem like within the context of the function call, wouldn’t it know insides GetMember() that member wasn’t initialized yet? I’m assuming it’s not only relying on static compile-time deduction, given the Run-Time Check Failure #3 it raises during execution, so based on my current understanding of it it would seem reasonable for the same checks to apply. Is this just a limitation of this specific compiler/debugger (Visual Studio 2008), or more tied to how C++ works?
You’ll probably notice that the warning is about
testnot being initialized. Which is why the warning & run-time failure only applies to the lineThis leads to undefined behavior, and, at least in debug mode, MSVS does some checking and is able to crash (in release, the bug would probably be hidden and you’d just end up with a bogus value in
f1).The next line however doesn’t directly result in UB.
f1isn’t read, nor are any of its data members (directly). A method is called, and the compiler can’t know that the member function would yield UB on an un-initialized object. The function could just print something to the screen and not read any of the members, which would be OK. Well, the compiler could theoretically know because it sees the code, but it doesn’t dig that deep. A static code analyzer might alert you on the problem.