Practical Learning Logo

Managed Arrays

 

Introduction

An array is a series of items of similar types. The items are created as one variable but each can be identified with a representing number called an index. Like C++ inherited the concept of arrays from its parent the C language, Managed C++ inherited arrays from C++ but added some new features.

Managed C++ mainly considers two types of variables and consequently two types of arrays: managed and unmanaged. Unmanaged arrays are used as they would be in C++. Because Managed C++ reinforces the concept of garbage collection, Managed C++ implements a new type of arrays.

Managed Arrays

A managed array is one that would be cleaned by the garbage collector when the array is not used any more. This means that you can rely on the garbage collector to reclaim the memory that the array was using.

In C++, when declaring an array, you must specify the dimension of the array. In Managed C++, when declaring a managed array, you are not allowed to specify the dimension of the array. Unlike regular variables, that  is, variables declared with primitive types, but like managed classes, to declare a managed array, you use the new operator and optionally the __gc keyword. Here is an example:

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
{
	 System::Int32 Population[] = __gc new System::Int32[5];
}

As you can see, you use the new operator to specify the dimension of the array. In this declaration, the __gc keyword is optional. If you omit it, the compiler would still consider that you had declared a managed array and would act appropriately when the application exits. On the other hand, you cannot declare a managed array as static. In the following example, we declare a regular array of type double, a pointer to an array or type long and a managed array of type Int32, all of them as static:

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
{
	 // This works
	 static double Density[5];
	 static long *Area[5];
	 // This ain't working
	 static System::Int32 Population[] = __gc new System::Int32[5];
}

When this joint compiles, the managed array would produce an error.

After declaring a managed array, you can initialize its members exactly as you would a regular array:

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
{
	 static long *Area[5];
	 System::Int32 Population[] = __gc new System::Int32[5];

	 Area[0] = new long(9984670);
	 Area[1] = new long(7686850);
	 Area[2] = new long(803940);
	 Area[3] = new long(163610);
	 Area[4] = new long(2766890);

	 Population[0] = 32207113;
	 Population[1] = 19731984;
	 Population[2] = 150694740;
	 Population[3] = 9924742;
	 Population[4] = 38740807;
			 
	 this->txtArea->Text = Area[2]->ToString();
	 this->txtPopulation->Text = Population[2].ToString();
}
 

An Array Variable of a Managed Class

Most, if not all, of the classes you will use in Visual C++ .Net but be declared as pointers. This was not the case in MFC but those who have used Borland C++ Builder are quite familiar with this because in the VCL also, each class must be declared as a pointer (with the exception of regular classes like AnsiString, TDateTime, etc and class from the Win32 library). In the same way, if you want to use an array of a .Net managed class, you must declare the array as a pointer.

Managed C++ uses a slightly different approach to declare a managed array of a class type. Here is an example that declares an array or 5 strings of type String:

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
		 {
			 String *strCountryName[] = __gc new String*[5];
		 }

Once again, the __gc keyword is optional: omitting it would produce the same effect. To initialize this type of variable, especially for the String type we have used, you can simply assign a string value to each member of the array, based on its index:

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
		 {
			 String       *strCountryName[] = __gc new String*[5];
			 String       *strCapital[]            =      new String*[5];
			 long          Area[5];
			 System::Int32 Population[]     = __gc new System::Int32[5];

			 strCountryName[0] = S"Canada";
			 strCountryName[1] = S"Australia";
			 strCountryName[2] = S"Pakistan";
			 strCountryName[3] = S"Tunisia";
			 strCountryName[4] = S"Argentina";

			 strCapital[0] = S"Ottawa";
			 strCapital[1] = S"Canberra";
			 strCapital[2] = S"Islamabad";
			 strCapital[3] = S"Tunis";
			 strCapital[4] = S"Buenos Aires";

			 Area[0] = 9984670;
			 Area[1] = 7686850;
			 Area[2] = 803940;
			 Area[3] = 163610;
			 Area[4] = 2766890;

			 Population[0] = 32207113;
			 Population[1] = 19731984;
			 Population[2] = 150694740;
			 Population[3] = 9924742;
			 Population[4] = 38740807;

			 this->txtName->Text       = strCountryName[2];
			 this->txtArea->Text       = Area[2].ToString();
			 this->txtPopulation->Text = Population[2].ToString();
			 this->txtCapital->Text    = strCapital[2];
		 }
  

A Managed Array as a Member Variable

It is quite easy to declare an array of a regular C++ data type as a member variable. Managed C++ imposes other rules. Imagine you create a structure as follows:

namespace WinForms1
{
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	__gc struct CCountry
	{
		String *Name;
		System::Int32 Area;
		System::Int32 Population;
		String *Capital;
	};

	/// <summary> 
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the 
	///          'Resource File Name' property for the managed resource compiler tool 
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public __gc class Form1 : public System::Windows::Forms::Form
	{

Once again, in Managed C++, when you declare an array, you cannot use the name of the variable to specify the dimension of the array. The same rule applies to an array declared as a member variable. Therefore, unlike C++, the following declaration is not allowed:

public __gc class Form1 : public System::Windows::Forms::Form
	{	
	public:
		Form1(void)
		{
			InitializeComponent();
		}
		
	private:
		CCountry *Country[5];
. . .

Since you are not allowed to specify the dimension of the array, once again, you can use the new operator to do that:

public __gc class Form1 : public System::Windows::Forms::Form
	{	
	public:
		Form1(void)
		{
			InitializeComponent();
		}
  
	private:
		CCountry *Country[] = __gc new CCountry*[5];

. . .

This type of declaration, which initializes a member variable in the body of a class, violates a rule that is presents even in C++. Because this initialization is necessary, Managed C++ allows you to initialize (only) a static member variable in the body of a class. Therefore, the array member variable must be declared as static:

public __gc class Form1 : public System::Windows::Forms::Form
	{	
	public:
		Form1(void)
		{
			InitializeComponent();
		}
  
	private:
		static CCountry *Country[] = __gc new CCountry*[5];

. . .

With this declaration completed, the array is ready. To initialize the array, you use the exact same approach as C++: 1) you initialize each member of the array with the new operator, 2) then you initialize each member of the class or structure by simply assigning it the desired value. Here is an example:

#pragma once

namespace WinForms1
{
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	__gc struct CCountry
	{
		String *Name;
		System::Int32 Area;
		System::Int32 Population;
		String *Capital;
	};

	/// <summary> 
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the 
	///          'Resource File Name' property for the managed resource compiler tool 
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public __gc class Form1 : public System::Windows::Forms::Form
	{	
	public:
		Form1(void)
		{
			InitializeComponent();
		}
  
	private:
		static CCountry *Country[] = __gc new CCountry*[5];

	protected:
		void Dispose(Boolean disposing)
		{
			if (disposing && components)
			{
				components->Dispose();
			}
			__super::Dispose(disposing);
		}
	private: System::Windows::Forms::Label *  label1;
	private: System::Windows::Forms::Label *  label2;
	private: System::Windows::Forms::Label *  label3;
	private: System::Windows::Forms::Label *  label4;
	private: System::Windows::Forms::TextBox *  txtName;
	private: System::Windows::Forms::TextBox *  txtArea;
	private: System::Windows::Forms::TextBox *  txtPopulation;
	private: System::Windows::Forms::TextBox *  txtCapital;

	private: System::Windows::Forms::Button *  btnClose;
	private: System::Windows::Forms::Button *  btnAccess;
	private: System::Windows::Forms::DataGrid *  dataGrid1;

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container * components;

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->label1 = new System::Windows::Forms::Label();
			this->label2 = new System::Windows::Forms::Label();
			this->label3 = new System::Windows::Forms::Label();
			this->label4 = new System::Windows::Forms::Label();
			this->txtName = new System::Windows::Forms::TextBox();
			this->txtArea = new System::Windows::Forms::TextBox();
			this->txtPopulation = new System::Windows::Forms::TextBox();
			this->txtCapital = new System::Windows::Forms::TextBox();
			this->btnClose = new System::Windows::Forms::Button();
			this->btnAccess = new System::Windows::Forms::Button();
			this->dataGrid1 = new System::Windows::Forms::DataGrid();
			(__try_cast<System::ComponentModel::ISupportInitialize *  >(this->dataGrid1))->BeginInit();
			this->SuspendLayout();
			// 
			// label1
			// 
			this->label1->Location = System::Drawing::Point(16, 16);
			this->label1->Name = S"label1";
			this->label1->Size = System::Drawing::Size(48, 23);
			this->label1->TabIndex = 0;
			this->label1->Text = S"Name:";
			// 
			// label2
			// 
			this->label2->Location = System::Drawing::Point(16, 48);
			this->label2->Name = S"label2";
			this->label2->Size = System::Drawing::Size(48, 23);
			this->label2->TabIndex = 1;
			this->label2->Text = S"Area:";
			// 
			// label3
			// 
			this->label3->Location = System::Drawing::Point(16, 112);
			this->label3->Name = S"label3";
			this->label3->Size = System::Drawing::Size(64, 23);
			this->label3->TabIndex = 2;
			this->label3->Text = S"Capital:";
			// 
			// label4
			// 
			this->label4->Location = System::Drawing::Point(16, 80);
			this->label4->Name = S"label4";
			this->label4->Size = System::Drawing::Size(64, 23);
			this->label4->TabIndex = 3;
			this->label4->Text = S"Population:";
			// 
			// txtName
			// 
			this->txtName->Location = System::Drawing::Point(88, 16);
			this->txtName->Name = S"txtName";
			this->txtName->TabIndex = 4;
			this->txtName->Text = S"";
			// 
			// txtArea
			// 
			this->txtArea->Location = System::Drawing::Point(88, 48);
			this->txtArea->Name = S"txtArea";
			this->txtArea->TabIndex = 5;
			this->txtArea->Text = S"";
			// 
			// txtPopulation
			// 
			this->txtPopulation->Location = System::Drawing::Point(88, 80);
			this->txtPopulation->Name = S"txtPopulation";
			this->txtPopulation->TabIndex = 6;
			this->txtPopulation->Text = S"";
			// 
			// txtCapital
			// 
			this->txtCapital->Location = System::Drawing::Point(88, 112);
			this->txtCapital->Name = S"txtCapital";
			this->txtCapital->TabIndex = 7;
			this->txtCapital->Text = S"";
			// 
			// btnClose
			// 
			this->btnClose->Location = System::Drawing::Point(112, 152);
			this->btnClose->Name = S"btnClose";
			this->btnClose->TabIndex = 9;
			this->btnClose->Text = S"Close";
			this->btnClose->Click += new System::EventHandler(this, btnClose_Click);
			// 
			// btnAccess
			// 
			this->btnAccess->Location = System::Drawing::Point(16, 152);
			this->btnAccess->Name = S"btnAccess";
			this->btnAccess->TabIndex = 10;
			this->btnAccess->Text = S"Access";
			this->btnAccess->Click += new System::EventHandler(this, btnAccess_Click);
			// 
			// dataGrid1
			// 
			this->dataGrid1->DataMember = S"";
			this->dataGrid1->HeaderForeColor = System::Drawing::SystemColors::ControlText;
			this->dataGrid1->Location = System::Drawing::Point(16, 192);
			this->dataGrid1->Name = S"dataGrid1";
			this->dataGrid1->Size = System::Drawing::Size(296, 168);
			this->dataGrid1->TabIndex = 11;
			// 
			// Form1
			// 
			this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
			this->ClientSize = System::Drawing::Size(370, 392);
			this->Controls->Add(this->dataGrid1);
			this->Controls->Add(this->btnAccess);
			this->Controls->Add(this->btnClose);
			this->Controls->Add(this->txtCapital);
			this->Controls->Add(this->txtPopulation);
			this->Controls->Add(this->txtArea);
			this->Controls->Add(this->txtName);
			this->Controls->Add(this->label4);
			this->Controls->Add(this->label3);
			this->Controls->Add(this->label2);
			this->Controls->Add(this->label1);
			this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
			this->MaximizeBox = false;
			this->MinimizeBox = false;
			this->Name = S"Form1";
			this->Text = S"Countries Statiistics";
			(__try_cast<System::ComponentModel::ISupportInitialize *  >(this->dataGrid1))->EndInit();
			this->ResumeLayout(false);

		}

private: System::Void btnAccess_Click(System::Object *  sender, System::EventArgs *  e)
		 {
			 Country[0] = __gc new CCountry;
			 Country[0]->Name = S"Canada";
			 Country[0]->Area = 9984670;
			 Country[0]->Population = 32207113;
			 Country[0]->Capital = S"Ottawa";

			 Country[1] = new CCountry;
			 Country[1]->Name = S"Australia";
			 Country[1]->Area = 7686850;
			 Country[1]->Population = 19731984;
			 Country[1]->Capital = S"Canberra";

			 Country[2] = new CCountry;
			 Country[2]->Name = S"Pakistan";
			 Country[2]->Area = 803940;
			 Country[2]->Population = 150694740;
			 Country[2]->Capital = S"Islamabad";
			 
			 Country[3] = new CCountry;
			 Country[3]->Name = S"Tunisia";
			 Country[3]->Area = 163610;
			 Country[3]->Population = 9924742;
			 Country[3]->Capital = S"Tunis";

			 Country[4] = new CCountry;
			 Country[4]->Name = S"Argentina";
			 Country[4]->Area = 2766890;
			 Country[4]->Population = 38740807;
			 Country[4]->Capital = S"Buenos Aires";

			 this->txtName->Text       = Country[4]->Name;
			 this->txtArea->Text       = Country[4]->Area.ToString();
			 this->txtPopulation->Text = Country[4]->Population.ToString();
			 this->txtCapital->Text    = Country[4]->Capital;
		 }

private: System::Void btnClose_Click(System::Object *  sender, System::EventArgs *  e)
		 {
			 Close();
		 }

};
}
   

Home Copyright © 2002-2010 FunctionX, Inc.