C++/CLI revision of the Managed Extension Reference Array Syntax
The declaration of a managed array object in the original language design was a slightly non-intuitive extension of the standard array declaration in which a __gc keyword was placed between the name of the array object and its possibly comma-filled dimension, as in the following pair of examples,
using namespace System;
void PrintValues( Object* myArr __gc[]);
void PrintValues( int myArr __gc[,,]);
This has been simplified in the revised language design, in which we use a template-like declaration to mirror the STL vector declaration. The first parameter indicates the element type. The second parameter specifies the array dimension [defaults to 1, of course]. The array object itself is a reference type and so must be given a hat. If the element type is also a reference type, then that, too, must be so marked. For example, the above example, when expressed in C++/CLI, looks as follows:
using namespace System;
void PrintValues( array<Object^>^myArr );
void PrintValues( array<int, 3>^myArr );
Because a reference type is a tracking handle rather than an object, it is possible to specify it as the return type of a function. The syntax for doing this was criticized in the original language design again as being somewhat non-intuitive. For example,
using namespace System;
Int32 f() [];
int GetArray() __gc[];
int GetArray() __gc[]
{
int a1 __gc[];
return a1;
}
This has also benefit from the revised declarative language syntax. The example, above, when translated into C++/CLI, looks as follows:
using namespace stdcli::language;
using namespace System;
array<Int32>^ f();
array<int>^ GetArray();
array<int>^ GetArray()
{
array<int>^a1;
return a1;
}
The actual definition of the array type is contained within the stdcli::language namespace, although the final identifier for this namespace, and whether it will be autogenerated by the compiler [this was auto-generated by a translation tool] or require user specification is currently under discussion in the ECMA standardization process.
Of course, the definition of GetArray is a dismal failure since it is returning a null tracking handle! One of the pitfalls of using the dynamic programming paradigm is adjusting to the CLR reference type semantics which, from an ISO C++ point of view, are topsy-turvy. The correct implementation is to return the object by gcnew, and not to fret over who owns the handle – the CLR garbage collector owns it. [The reason the revised language provides a deterministic finalization mechanism through a steroid destructor mechanism is not for the automation of memory management – Give GC a Change, as the late John Lennon once wrote, if memory serves me – but to handle the automatic reclamation of other system resources that are not recognized by the underlying CLR.]
The explicit initialization of a managed array supported within the original language is maintained in the revised syntax. For example, the following two initialized declarations,
int myIntArray __gc[] = { 1, 2, 3, 4, 5 };
Object* myObjArray __gc[] =
{
__box(26)
,
__box(27)
,
__box(28)
,
__box(29)
,
__box(30)
};
looks as follows in C++/CLI:
using namespace System;
array<int>^myIntArray = {1,2,3,4,5};
array<Object^>^myObjArray = {26,27,28,29,30};
The allocation of an array object on the heap, in the original language design, looks as follows:
using namespace System;
Object* myArray[] = new Object*[2];
String* myMat[,] = new String*[4,4];
In C++/CLI, the new expression is replaced with gcnew, and the dimension sizes are passed as parameters to the gcnew expression, as follows:
using namespace System;
array<Object^>^myArray = gcnew array<Object^>(2);
array<String^,2>^myMat = gcnew array<String^,2>(4,4);
I believe it is permitted in the new language to provide an explicit initialization list following the gcnew expression [but I am not going to unfathomably confirm that – this is, after all, a blog, and new language features generally fall outside my charter – see Herb Sutter or Brandon Bray’s blogs for details].
In the original language design, there was no explicit support for the param array that C# supports. Instead, one flags an ordinary array with an attribute, as follows:
void Trace1( String* format, [ParamArray]Object* args[] );
void Trace2( String* format, Object* args[] );
While these both look the same, the ParamArray attribute tags this for C# or other .NET languages as an array taking a variable number of elements with each invocation. In C++/CLI, the design for directly supporting this looked as follows:
void Trace1( String^ format, ... array<Object^>^ args );
void Trace2( String^ format, array<Object^>^ args );
in which the ellipsis […] preceding the array declaration tags it as a param array. Unfortunately, this has recently failed to make the list of features to be implemented for the inaugural release of C++/CLI. However, I can’t bear to [at least as yet] remove it from the translation tool.
Comments
- Anonymous
February 17, 2004
As much as I already love the new syntax, I must confess that I'm suprised by this new ... syntax:
void Trace1( String^ format, ... array<Object^>^ args );
Could you or someone else on the team explain what the reasoning behind it was?
Thanks. - Anonymous
February 17, 2004
ewwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww - Anonymous
June 13, 2009
PingBack from http://outdoordecoration.info/story.php?id=3309