Last Updated:

Packing and Unpacking Primitive Data Types | C++

Packaging and unpacking is an important programming concept in .NET, regardless of which programming language you are using. One of the most important advantages of .NET is a unified type system. Each type, including simple packaged inline types such as _box (int), is a descendant of the System.Object class. In languages like Smalltalk, all types are objects, but this makes it inefficient to use simple types.

Packing and Unpacking Primitive Data Types

In standard C++, simple built-in data types and objects are handled differently, which increases the efficiency of using types, but eliminates the possibility of unifying the type system. Managed C++ combines the benefits of both approaches using a technique called boxing. Packaging–Converting value types, such as int or double (with double precision), into a reference to an object stored in a dynamically allocated memory area.

Packaging is done using the keyword _box. Decompression – Converts a packaged type (stored in a dynamically allocated memory area) to an unpackaged value (stored on the stack). Unpacking is performed by type conversion.

Let's illustrate the packaging and unpacking with the following code snippet:

int x = 5; // simple built-in type int
_box int *po = _box(x); // package
x = *ro; // unpacking

The _box keyword creates a managed object in a managed dynamically allocated memory area that encapsulates a copy of an expression of a value type. An expression of a value type refers to a primitive data type, such as intfloatdouble, or char, or a value type defined as a class or structure and described using the keyword _value (value). For example, a predefined managed type _boxed_System_Int32 encapsulates a packaged int, and a managed type _boxed_ValueStruct encapsulates a packaged value type named ValueStruct.

These strange type names (_boxed_System_Int32 and _boxed_ValueStruct) won't necessarily appear in your source code, but they are shown by the Ildasm.exe utility. Note that the int* _box is the alternate name of the _boxed_System_Int32 managed type, and the ValueStruct* _box is the alternate name of the _boxed_ValueStruct managed type.

If the _box keyword is used to create a managed object, the .NET garbage collector will automatically release the memory used by that object. This is similar to the concept of using interface classes for primitive types, but packaging is more important in .NET than in regular C++ programming. This is because objects in C++ can be used both as values and as reference types, whereas in .NET managed objects are always reference types (that is, references or pointers to objects stored in a managed dynamically allocated memory area).

You access value types in the same way that you access unpackaged types. In the code below, this is done by assigning plntBox = 50. Although plntBox points to a managed object, the dereferenced pointer is used as if it were simply a pointer to an unpackaged int type.

//BoxExample.cpp
#using <mscorlib.dll>
using namespace System;
// use namespace System;
_value struct ValueStruct
{
public:
int i;
};
// function expects to receive a managed object pointer
void ExpectManagedObjectPointer(
_boxValueStruct*pManagedObject)
{
pManagedOb]ect › i = 20; // modifies the boxed copy
Console::WriteLine(pManagedObject › i);
}
// function expects to receive a managed object pointer
void ExpectBoxedPrimitivePointer(_box int* plntBox)
{
*pIntBox = 50; //modifies the boxed copy of the primitive type
Console::WriteLine(*pIntBox);
}
void main(void)
{
ValueStruct ValueStruct; // object of type value on the stack
ValueStruct.i = 10; // changes the original unpacked copy
Console::WriteLine(ValueStruct.i);
_box ValueStruct* pManagedObject
= _box(valueStruct); //_boxed_ValueStruct
ExpectManagedObjectPointer(pManagedObject);
pManagedObject › i = 30;* // modify the packed copy
Console::WriteLine(pManagedObject › i);
int j; // value type - primitive data type
j = 40; // changes the original unpacked
// primitive type
Console::WriteLine(j);
_box int *p!ntBox = _box(j); // packed_System_Int32
ExpectBoxedPrimitivePointer(plntBox);
}

The above program will print:

10
20
30
40
50