Pointers. Part 6. Composite managed and native data types. Managed pointers (^) in the CLR. Memory allocation. The ref and value qualifiers. Managed pointers (^) to structures and classes

Pointers. Part 6. Composite managed and native data types. Managed pointers (^) in the CLR. Memory allocation. The ref and value qualifiers. Managed pointers (^) to structures and classes


1. What features of the organization of composite data types in a CLR (Common Language Runtime) environment?

In C++ (Visual C++), there are two types of composite data types:

  • native data types. Pointers to these types of data are denoted by *;
  • data types for working in the Common Language Runtime (CLR).

These types are also called managed data types. These types of data are stored in memory, which is allocated by the CLR environment.

Objects of these data types must be located in the dynamic memory, which is managed by the CLR. Pointers to such memory are indicated by the symbol ^.

2. What are the features of using composite native data types?

The composite native data types include:

  • native structures;
  • native classes.

To access these data types is used an unmanaged pointer *.

The work of unmanaged pointers is described in more detail in the following topics:

3. What are the features of using managed composite data types?

Managed composite data types are:

  • managed structures;
  • managed classes.

Such structures and classes are designed to work in the CLR environment. They are placed in the memory that is allocated and managed by the CLR. If the programmer creates a project of the type “CLR Console Application” or “Windows Forms Application”, then this project meets the requirements of the CLR.

Objects that are managed by the CLR environment fall into managed dynamic memory. When declaring a pointer to a managed-structure or managed-class, the character ^ is used. The memory for this pointer is allocated by the gcnew utility.

4. What qualifiers are used to declare structures and classes in the CLR?

In a CLR environment, structures and classes can have two qualifiers:

  • qualifier ref – means that the structure or class is a reference type;
  • qualifier value – means that the structure or class is a value type.

In the CLR, you can also declare a structure or class without a qualifier. Working with such structures is used for compatibility with pointers to structures of older versions of C/C++.

5. What is the difference between ref and value qualifiers when declaring structures or classes? Examples of accessing to ref structures and value structures using a pointer

The difference between the ref and value qualifiers is the way the memory is allocated for a pointer to a structure or class.

With the ref modifier, the structure or class is placed in a managed heap and can not be placed in the native heap.

With the value modifier, a structure or class can be placed in a managed heap and in a native heap.

The following examples demonstrate the difference between the structures that are described with the ref and value qualifiers. The same applies to classes.

Let’s use a structure that describes the pixel on the monitor screen.

Example 1. Declaration of structure with qualifier ref.

// structure declared with qualifier ref
ref struct MyPoint_ref
    int x;
    int y;
    int color;

Then, the use of a structure from another program code can be as follows:

// qualifier ref
// 1. Declaring a pointer to a structure with a ref qualifier
MyPoint_ref ^ pr;
// 2. Memory allocation for the pointer
//    Memory is allocated in a managed heap
pr = gcnew MyPoint_ref;

// 3. Filling the structure fields
pr->x = 28;
pr->y = 35;
pr->color = 2;

// Error!
// MyPoint_ref * p; - It is impossible to declare an unmanaged pointer to the ref-structure

Example 2. Declaring a structure with value qualifier.

// Structure declared with qualifier "value"
value struct MyPoint_value
    int x;
    int y;
    int color;

Use of structure

// qualifier value
// 1. Declaring pointers to a structure with a qualifier 'value'
MyPoint_value ^ p1; // managed-pointer
MyPoint_value * p2; // native-pointer

// 2. Memory allocation for pointers
p1 = gcnew MyPoint_value;
p2 = new MyPoint_value;

// 3. Demonstration of working with fields of structures through pointers
p1->x = 33;
p1->y = 200;
p1->color = 3;

p2->x = 10;
p2->y = p1->y;
p2->color = p1->color;

6. What access do fields and members of the structure or class have by default?

When a structure is declared, its fields (data members) and methods have a public access specifier.

When declaring a class, its data members and methods have a private access specifier.

7. An example of the declaration and use of a structure with a qualifier ref

Let the structure that is declared in the module “MyRefStruct.h” be given. The structure describes the coordinates of a point on a plane.

The structure is declared with the qualifier ref.

ref struct MyPointRef
    int x;
    int y;

An example of using a structure in a program using a managed pointer.

// declaration of structure with qualifier ref
MyPointRef ^mp; // pointer to the structure
mp = gcnew MyPointRef; // memory allocation for the structure

// access to the structure fields
mp->x = 25;
mp->y = 30;

8. How managed-arrays are declared in the CLR? Assignment of the keyword ‘array’

In C++, native arrays are declared in the usual way for the language. More details about arrays in C++ are described in the following articles:

To declare the managed array, use the keyword ‘array’.

9. An example of declaring and using an array of managed structures that are declared with a ref qualifier using a managed pointer (^)

Let the structure MyPointRef is declared in the module “MyRefStruct.h”, which describes the point on the coordinate plane

ref struct MyPointRef
    int x;
    int y;

Working with an array of 10 managed-structures like MyPointRef is shown below. First you need to include the structure file:

#include "MyRefStruct.h"

Allocation of memory for an array and filling the fields of structure from other program code (for example, the event handler for a click event on a button):

// An array of m pointers to a structure
// declared as managed with the keyword ref
array <MyPointRef^> ^m;

// memory allocation for 10 pointers
m = gcnew array <MyPointRef^>(10);

// creating 10 objects of the type "MyPointRef structure"
for (int i=0; i<10; i++)
    m[i] = gcnew MyPointRef; // memory allocating for i-th structure

// filling of fields x, y of array of structures
for (int i=0; i<10; i++)
    m[i]->x = i*5;
    m[i]->y = i*i;

If you declare a MyPointRef structure with a value qualifier, then this example will also work.

10. An example of declaring and using a managed-array on basic types (int, double) with a managed (^) pointer

The following example declares an array of 20 integers of type ‘int’. To do this, you use a managed pointer (^).The allocation of memory for the array occurs in 2 stages:

  1. Allocation of memory for 20 pointers to type int.
  2. The allocation of memory for each element of type int, to which pointers should point.

To declare array you need use the ‘array’ word.

// managed-array to base types
array <int ^> ^pi; // pi - Pointer to an array of types int
pi = gcnew array <int ^>(20); // Allocating memory for an array of 20 pointers

// allocating memory for each item of the array
for (int i=0; i<20; i++)
    pi[i] = gcnew int;  // allocating memory for the i-th element of the array

// using an array
for (int i=0; i<20; i++)
    pi[i] = i*5;

int d;
d = (int)pi[2]; // d = 10

11. An example of declaring and using an array of pointers (^) to a class that are declared as managed using the ref classifier and the keyword array

In the example, a class named MyClassRef is declared that describes the coordinates of the point on the plane. The class is declared as managed (has a ref qualifier). Class contains:

  • private data members x, y;
  • the constructor of class MyClassRef();
  • methods GetX() and GetY() that return values of data members x, y;
  • method SetXY(), which sets a new values of data members x, y;

The class is declared in two modules (files):

  • module “MyClassRef.h” – it contains a declaration of a class member data and methods;
  • module “MyClassRef.cpp” – it contains the implementation of class methods.

Text of module “MyClassRef.h”:

#pragma once

// the class is declared as managed
ref class MyClassRef
    // members of the class data
    int x; // the coordinate x
    int y; // the coordinate y

    // class methods
    int GetX(void);
    int GetY(void);
    void SetXY(int nx, int ny);

Text of module “MyClassRef.cpp”:

#include "StdAfx.h"
#include "MyClassRef.h"

// the constructor of class
    x = y = 0;

// class methods
int MyClassRef::GetX(void)
    return x;

int MyClassRef::GetY(void)
    return y;

void MyClassRef::SetXY(int nx, int ny)
    x = nx;
    y = ny;

To use the class methods from another program code, you must first connect the “MyClassRef.h” module:

#include "MyClassRef.h"

After that, you can use the methods of the class. Below is the declaration and use of an array of managed pointers (^) to a class from another program code:

// array mp of managed-pointers to the class MyClassRef
// first is allocated memory for 10 pointers
array <MyClassRef ^> ^mp = gcnew array <MyClassRef ^>(10);

// memory allocation for each pointer
for (int i=0; i<10; i++)
    mp[i] = gcnew MyClassRef;

// the use of class methods using an array of pointers
mp[1]->SetXY(5, 6);
mp[5]->SetXY(10, -200);

int d;
d = mp[1]->GetX(); // d = 5
d = mp[0]->GetY(); // d = 0
d = mp[5]->GetY(); // d = -200

Related topics