Initializing Arrays and Aggregates

Jordy posted a question to MSDN’s new forums website that I thought would be interesting to readers of my blog. Basically he wants to convert the following native C++ code to managed code:

class Constant
{
public:
    String Name;
    double Value;
};
 
static const Constant ConstTable[] =
{
    { "e", 2.718281828 },
    { "Pi", 3.14159265358979323846 },
    { "c", 299792458.0 }
};

There are a few aspects to this code that are worth noting as we look for a managed alternative:

  • The ConstTable declaration includes the static keyword which indicates that the array has static duration. It is also a global variable and as such will have internal linkage. Briefly this means that different instances of the ConstTable identifier will refer to the same identifier but only within the translation unit.
  • The Constant class is an aggregate and can be initialized with a comma-separated list of values in curly braces. Aggregate types don’t have constructors, non-public member variables, base classes or virtual functions.

Here is a simple solution using managed code:

value class Constant
{
public:
    String^ Name;
    double Value;
};
 
ref struct StaticClass abstract sealed
{
    static initonly array<const Constant>^ ConstTable =
    {
        { "e", 2.718281828 },
        { "Pi", 3.14159265358979323846 },
        { "c", 299792458.0 }
    };
};

A few things are worth noting: A value class is used for defining Constant since ref classes don’t qualify as aggregate types. Value classes are also more efficiently stored and accessed in memory and are stored continuously in the managed array. An abstract sealed class is used to house the static array since managed types cannot be global variables.

The storage and linkage options offered by native C++ are useful but can get tricky as applications are built from different libraries. The CLR provides a conceptually simpler model for defining types and variables even if not all of the flexibility of C++ is available to managed types.


© 2005 Kenny Kerr

1 Comment

  • What would you recommend if struct Constant were declared in &lt;windows.h&gt;? Should there be a new header with managed declaractions for every exisitng header with API declarations?



    In beta 1 in a managed class I defined some variables whose types are declared in &lt;windows.h&gt;, in other headers that are nested includes from &lt;windows.h&gt;, in &lt;setupapi.h&gt;, etc. Sometimes I defined them as static const with initializers, and other times they were really variables. When calling APIs, I defined some pinned pointers[*], pointed them at the variables that had native types, passed the pointers to APIs, and they worked. In beta 2 I can't even declare the variables.



    Is P/Invoke dead already? When we need to call an API we should code it in Native C++? Most APIs were callable from VB6 with Declare statements, and most can still be called from VB-- with enough Marshalling attributes. Is Managed C++ going to be even more cumbersome?



    [* In a blog of one of your colleagues I mentioned a wish that casts to pin_ptr types would be allowed in the parameters to a function call, instead of requiring the programmer to define a named pin_ptr variable and then keeping the thing pinned until exiting from the scope of the named pin_ptr variable. But after experimenting with beta 2, it seems my wish is even farther away than it used to be.]

Comments have been disabled for this content.