I have a C++/CLI project that declares a String^ variable inside a for loop but does not initialize it. On the first iteration, the variable is set to some value. On each subsequent
iteration, it appears to be retaining the previous value. Shouldn’t a variable in local scope be initialized to null (or equivalent) each time thru the loop? This happens with an int as well. Also, the compiler
does not warn of a potentially uninitialized value unless I set the warning level to W4, and even then it only warns for the int and not the String^.
This is sample code that shows the behavior.
#include "stdafx.h"
using namespace System;
int main(array<System::String ^> ^args)
{
for(int n = 0; n < 10; n++)
{
String^ variable;
int x;
switch(n)
{
case 1:
variable = "One";
x = 1;
break;
case 5:
variable = "Five";
x = 5;
break;
}
Console::WriteLine("{0}{1}", variable, x);
}
}
The output of this will be
One, 1
One, 1
One, 1
One, 1
Five, 5
Five, 5
Five, 5
Five, 5
Five, 5
Am I completely misunderstanding how locally scoped variables are supposed to be initialized? Is this a “feature” unique to managed C++? If I convert
this to C# the compiler will warn about both variables, even at the base warning level.
Disclaimer: I know C and C++ pretty well; C++/CLI, not so much. But the behavior you’re seeing is essentially the same that I’d expect for a similar program in C or C++.
String^is a handle to aString, similar to a pointer in C or C++.Unless C++/CLI adds new rules for initialization of handles, a block-scope variable of type
String^with no explicit initialization will initially have a garbage value, consisting of whatever happened to be in that chunk of memory.Each iteration of the loop conceptually creates and destroys any variables defined between the
{and}. And each iteration probably allocates its local variables in the same memory location (this isn’t required, but there’s no real reason for it not to do so). The compiler could even generate code that allocates the memory on entry to the function.So on the first iteration of your loop,
variableis set to"One"(or rather, to a handle that refers to"One"), that’s the value printed byConsole::WriteLine. No problem there.On the second iteration,
variableis allocated in the same memory location that was used for it on the first iteration. No new value is assigned to it, so it retains the value that was stored in that memory location on the first iteration. The same thing happens withx.You cannot count on the previous value being retained, and your program’s behavior is undefined. If your goal were to write a correctly working program, rather than to understand how this incorrect program behaves, the solution would be to ensure that all your variables are properly initialized before they’re used.
If you did the initial assignment on the second iteration rather than the first, the program would likely crash on the first iteration — though even that’s not guaranteed.
As for why the compiler doesn’t warn about this, I don’t know. I hesitate to suggest a compiler bug, but this could be one.
Also, even with high warning levels enabled, warning about uninitialized variables requires control flow analysis that may not be done by default. Enabling both warnings and a high level of optimization might give the compiler enough information to warn about both
variableandx.It still seems odd that it warns about
xand not aboutvariablewithW4.