The array template

Some background. In Managed Extensions, the CLI Array was exposed using the keyword __gc[]. If you wanted a CLI array of, say, ten ints named arr, you did: int arr __gc[] = new int __gc[10];. Then, access into the array worked much like native arrays. If I wanted the fifth element, I did arr[4]. (C++ arrays are zero-indexed, remember.) If I wanted access to the members of the CLI array, you used the -> operator. You might have code that looked like this:

#using <mscorlib.dll>

using namespace System;

int main(){

  int arr __gc[] = new int __gc[10];

  for(int i=0; i<arr->Length; i++)

    arr[i] = arr->Length-i; //inverse-load the array.

  arr->Sort(); //sort the array

  System::Console::WriteLine("This array has {0} members.",
__box(arr->Length));
}

So, why change it? Aside from that nasty __boxing (that in V2 is cured by implicit boxing), something doesn't seem quite right. It isn't consistent. In native C++, we're used to arrays being lightweight objects, a simple obfuscation of the pointer syntax. But, though it looks the same, creating a CLI array is a little different. First off, you have to new it. Second, it has these hidden members you access through the -> operator, although it isn't a pointer-type. The simple native array syntax doesn't seem robust enough to really describe the CLI array object.

 

So, what is the new array syntax? Its a template class, now. You declare a handle to it, and then gcnew it. The template parameter is the element type of the array, and you pass the constructor the size of the array. Let's look at the same code from before, in the new syntax:

using namespace stdcli::language;

int main(){

array<int>^ arr = gcnew array<int>(10);

for(int i=0; i<arr->Length; i++)

arr[i] = (arr->Length)-i; //inverse-load the array.

arr->Sort(); //sort the array

System::Console::WriteLine("This array has {0} members.", arr->Length);

}

This new version may seem, on the surface, to be a little more complex, but is also more consistent with the C++ language. Plus, people are already familiar with things like smart pointers, which are implemented in a similar fashion.

What about multi-dimensional arrays? Multi-dimensional arrays have been implemented as a second template parameter. Whereas the first template parameter is the type of the array, the second is the dimension of the array (default to 1). So, if I wanted a three-dimensional array of ints at 10x20x5, I'd do: array<int, 3>^ arr = gcnew array<int, 3>(10, 20, 5); And to access elements: arr[3][6][2].

In short, the old array syntax was perhaps a little less complex, but it was also more confusing. We give up a little of that simplicity for more consistency. No more “hidden” objects, here.