Click here to Skip to main content
15,614,421 members
Articles / Programming Languages / C++/CLI
Posted 16 Apr 2001


19 bookmarked

Using value types in managed C++

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
15 Oct 2001CPOL3 min read
A quick introduction to using .NET value types in managed C++


Managed reference types in .NET are objects that contains methods and properties and which live their lives on the .NET managed heap. There are situations, however, where you do not want the overhead associated with creating and destroying objects on the heap. When dealing with simple data structures such as an integer or an (x,y) coordinate it is far more convenient - and efficient - to allocate these values directly on the stack and work with them using the standard value type semantics. No one wants to have to write
int* n = new int();

when declaring an integer (or array of 10,000 integers!). Instead, primitive types such as numeric types, boolean, char and date, structures and enumerations are all declared as value types, meaning they are allocated on the stack and declared and accessed as you would a structure or stack-based variable in standard C++.

Declaring and Creating Value Types

To declare a value type in managed C++ you use the new __value keyword. For instance, if we wished to create a data type to represent complex numbers we could declare the following:

__value struct Complex
    double real;
    double imaginary;

Value types are created on the stack and are accessed directly. Value types are declared

Complex z;

and their members accessed using the . syntax

z.real = 1.0;
z.imaginary = -3.1415;

Once the memory containing a value type is freed, the value type instance is destroyed. Hence, references to value types are not allowed. If it were allowed it would be possible to have a reference point to an invalid memory location. A value type will always point to a variable of that type, and cannot be null. Assigning a value type to another variable results in a copy of the value being made.

Because value types are managed types, they are initialised to 0 when they are created. Value types can contain reference types, though these reference types will be created on the managed heap and the reference to them stored on the stack.

Value types implicitly inherit from System.ValueType, and their use is encouraged for types that act like primitive data types, types that are small, types that do not inherit from, or are inherited by, other data types, and types that are not frequently passes as parameters (this would cause a lot of memory allocation and copying). Value types can inherit from managed interfaces, and can override virtual methods defined therein.

One important point with all value types is that they do can contain methods and fields, and you can override virtual methods from base interfaces. For instance, we may wish to override the ToString method for our complex type so that we can present it in a formatted manner

__value struct Complex
    double real;
    double imaginary;

    virtual String *ToString()
        return String::Format("{0} + {1}i", real.ToString("N2"), imaginary.ToString("N2"));

Boxing and Unboxing

Boxing is a feature that allows a value type to be passed around as a reference type. For instance, one of the the standard Format method overrides of the .NET String class takes a format string and an object.

public: static String* Format(String*, Object*);

The format string specifies the format, and the object is accessed within that format string using the {0} syntax. An int is not derived from Object and hence cannot normally be passed to this function. However, by boxing an integer value we are creating an object that will contain the value of the integer and can be used as an object. The syntax is

object obj = __box(5);

This creates a managed reference on the managed heap containing the value '5'. This object can now be used wherever an Object* object is required.

We can also declare boxed value types like

__box Complex* pZ = __box(z);

This gives us an object we can use in whatever way we deem fit, but in doing so we retain the ability to access the underlying type's data fields

pZ->real = 4;

Once we are done using the value in its boxed form we can unbox the value using the C++ dynamic_cast operator

Complex w = * dynamic_cast<Complex*>(pZ);


26 Apr 2001 - added sample app

16 Oct 2001 - updated source for VS.NET beta 2


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Founder CodeProject
Canada Canada
Current passion project: CodeProject.AI Server. Please join in!

Chris is the Co-founder of the popular code-sharing site, the digital advertising agency and the content marketing agency ContentLab.IO.

He's been programming way too long and has been, in various guides, an astrophysicist, mechanic, mathematician, physicist, breeder of carnivorous plants, hydrologist, geomorphologist, defence intelligence researcher and then, when all that got a bit rough on the nerves, a serial entrepreneur.

Chris has programmed everything from FORTRAN on a CRAY to Python on a Pi, but generally leans on TypeScript, C#, and SQL for the front, middle and back bits of his applications. His current focus is on ensuring developers know enough about Artificial Intelligence to be dangerous.

Comments and Discussions

-- There are no messages in this forum --