referencec++-clidefault-valuenullptrautomatic-storage

C++/CLI reference not initialized to nullptr on subsequent entries into local block


I thought in C++/CLI declaring a local reference variable without an explicit initial value always initialized it to nullptr. I'm finding that this doesn't occur on the second and later entries into a local block. Here's the sample code.

void main()
{
    for (int i=0; i<6; i++)
    {
        switch (i)
        {
        case 2:
            Console::WriteLine("i={0} localI and hashTable no longer in scope", i);
            break;
        default:
            {
                // Declare local reference variable
                Hashtable^ hashTable;
                Int32 localI;

                Console::WriteLine("i={0} localI={1}  {2}",
                    i, localI, 
                    hashTable == nullptr ? "hashTable=nullptr" : "hashTable NOT SET to nullptr"
                                   );
                hashTable = gcnew Hashtable();
                localI = i+1;
            }
            break;
        }
    }
}

The output from this is:

i=0 localI=0  hashTable=nullptr
i=1 localI=1  hashTable NOT SET to nullptr
i=2 localI and hashTable no longer in scope
i=3 localI=2  hashTable NOT SET to nullptr
i=4 localI=4  hashTable NOT SET to nullptr
i=5 localI=5  hashTable NOT SET to nullptr

If I add explicit initialization

Hashtable^ hashTable = nullptr;
Int32 localI = 99;

Then each loop reinitializes the reference and localI

i=0 localI=99  hashTable=nullptr
i=1 localI=99  hashTable=nullptr
i=2 localI and hashTable no longer in scope
i=3 localI=99  hashTable=nullptr
i=4 localI=99  hashTable=nullptr
i=5 localI=99  hashTable=nullptr

This seems to contradict what I found here on MSDN which says:

"The following code example shows that when handles are declared and not explicitly initialized, they are default initialized to nullptr."


Solution

  • This is by design, the CLR only initializes local variables on method entry. Scope blocks inside a method are a language implementation detail that disappears after compilation. Other managed languages are alike, VB.NET behaves the exact same way. C# would too, but doesn't permit this kind of code due to its definite assignment rule.

    This behavior otherwise simplifies the runtime implementation greatly. The jitter simply generates code to blast the stackframe to zero at entry.