В отличие от массивов в обычном C++, которые являются простым типом указателя, управляемые массивы являются полноценными управляемыми объектами, расположенными в динамически распределяемой области. System: : Array (Система::Массив) — абстрактный класс, являющийся базовым для всех управляемых массивов. Для определения неуправляемых массивов можно использовать синтаксис обычного C++; для определения же управляемых массивов следует использовать либо ключевое слово _дс (сборщик мусора), либо указывать, что элементы массива относятся к управляемому типу. Далее приведены примеры определения массивов. Ключевое слово _дс (сборщик мусора) и управляемые типы подробнее рассмотрены ниже. Обратите внимание на две закомментированные строки, в которых при определении массива задается его величина. Величину массива можно задавать при определении неуправляемого (располагаемого в стеке) массива, но не при определении управляемого массива (располагаемого в динамически распределяемой области). Причина в том, что, подобно всем остальным управляемым типам, управляемый массив располагается в динамически распределяемой области, а не в стеке.
//ArraySyntax.срр
fusing <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
ttpragma warning(disable : 4101)
// уничтожить предупреждение о переменной, на которую нет ссылки:
// предупреждение (отключить: 4101)
void main(void) {
// традиционный синтаксис неуправляемого массива
int *pintUnManagedArrayOnHeap = new int [5];
int intUnManagedArray[5]; // нет ошибки для неуправляемого
// массива
// синтаксис управляемого массива,
// используется ключевое слово _дс (сборщик мусора) int intManagedArrayOnHeap _дс[] = new int _дс[5]; //int intManagedArray _gc[5]; // ошибка для управляемого
// массива
// синтаксис управляемого массива, используется
// управляемый тип элемента
String *strManagedArrayOnHeap[] = new String* [5]; // Строка
//String *strManagedArray[5]; // ошибка для управляемого
// массива }
Управляемые массивы имеют некоторые дополнительные, по сравнению с неуправляемыми массивами, свойства и ограничения.
Следующий пример показывает, как можно использовать обработчик исключений при попытке доступа к несуществующему элементу управляемого массива. Обратите внимание, что массив содержит пять элементов, а в цикле производится попытка установить значение шестого. Программа в обычном C++ выполнила бы такое действие, изменив содержимое памяти за пределами массива. Никто не скажет точно, чем это могло бы закончиться. При проверке корректности адреса выполняются два действия: во-первых, предотвращается изменение содержимого памяти за пределами массива; во-вторых, программе сообщается, что возникла подобная ситуация, тем самым давая возможность исправить ошибку еще на стадии тестирования. В обычном C++ такая ошибка часто не проявляется до тех пор, пока программа, по непонятным причинам, не прекращает работу, обычно в месте кода, далеко отстоящем от самой ошибки. И, разумеется, согласно закону Мэрфи, эта ошибка обнаруживается только тогда, когда программа уже передана заказчику. //IndexOutOfRangeException.срр
#using <mscorlib.dll> using namespace System;
// использовать пространство имен Система/void main () {
int intArray _gc[]= new int _gc[5]; // сборщик мусора [5]
for (int i=0; i<6; i++) // больше чем есть!!!
{
try {
intArray[i] = i; }
catch (IndexOutOfRangeException *piore) {
// нужно сделать кое-что более полезное, // чтобы здесь восстановиться Console::WriteLine("Oooops!"); Console::WriteLine(piore->get_Message()); } } }
Программа напечатает:
Oooops!
Exception of type System.IndexOutOfRangeException was thrown.
Перевод такой [Добавлен редактором русского перевода. — Прим. ред.]:
Возникло исключение типа Система.IndexOutOfRangeException.
Как и для неуправляемых массивов, нумерация элементов в управляемых массивах начинается с нуля. Однако, значения элементов управляемых массивов, в отличие от элементов неуправляемых массивов, автоматически инициализируются значением, принятым по умолчанию для каждого типа элемента массива. Переменным примитивных типов, таких, как int, char (символ), float (с плавающей точкой) и double (с удвоенной точностью) присваивается нуль. Элементам, указывающим на управляемые объекты, также по умолчанию присваивается нулевое значение (т.е. нулевой указатель). Элементы значимых типов инициализируются с помощью их принятого по умолчанию конструктора (т.е. конструктора, не имеющего аргументов). Значимые типы подробнее рассмотрены ниже.
В следующем примере иллюстрируется работа с массивами, и сравниваются управляемый двумерный массив и обычный неуправляемый двумерный же массив. Обратите внимание, что при работе с неуправляемым массивом используется старый синтаксис доступа к элементам массива [ ] [ ], тогда как при работе с управляемым массивом, который является истинно двумерным, используется синтаксис [, ]. Хотя в этом примере при использовании синтаксиса [ ] [ ] каждый из подмассивов имеет одинаковое количество элементов, в других случаях они могут иметь разные размеры (т.н. массив с неровным правым краем). Синтаксис [, ] предполагает использование истинно прямоугольного массива.
//Arrayl.срр
fusing <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
void main () {
// управляемый одномерный массив int
// (использующий сборщик мусора)
Console::WriteLine("managed ID array of int");
// ("управляемый одномерный массив int");
int intArray _gc[]= new int _gc[5];
for (int i=0; i<intArray->Length; i++)
{
intArray[i] = i;
Console::Write(intArray[i]); // Запись
Console::Write("\t"); // Запись } Console::WriteLine();
// управляемый двумерный массив Строк
// (использующий управляемый тип)
Console::WriteLine("managed 2D array of Strings");
// ("управляемый двумерный массив Строк ");
String *str2DArray[,] = new String *[2,3]; // новая Строка
for(int row=0; row<str2DArray->GetLength(0); row++)
//по строкам
{
for(int col=0; col<str2DArray->GetLength(l) ; col++)
//по столбцам
{
str2DArray[row,col] = (row*10 + col).ToString();
// str2DArray [строка, столбец] = (row*10 + столбец)
// .ToString ();
Console::Write(str2DArray[row,col]);
// Запись:: (str2DArray [строка, столбец]);
Console::Write("\t"); // Запись }
Console::WriteLine(); }
// неуправляемый двумерный массив int (для сравнения)
Console::WriteLine("unmanaged 2D array of int");
// ("неуправляемый двумерный массив int");
int int2DArray[2][3];
for(int row=0; row<2; row++) //по строкам
{
for (int col=0; col<3; col++) // по столбцам {
int2DArray[row][col] = row*10 + col;
// int2DArray [строка] [столбец] = row*10 + столбец; Console::Write(int2DArray[row][col]); // Запись:: (int2DArray [строка] [столбец]); Console::Write("\t"); // Запись }
Console::WriteLine(); } )
Результат работы программы приведен ниже. Управляемый прямоугольный двумерный массив содержит элементы типа String*, а неуправляемый — элементы типа int. Однако управляемый массив может также содержать и элементы неуправляемых типов, между тем как неуправляемый массив — лишь элементы неуправляемых типов.
managed ID array of int 01234 managed 2D array of Strings 012 10 11 12
unmanaged 2D array of int
0 1 2
10 11 12
Перевод такой:
управляемый одномерный массив int
01234
управляемый двумерный массив Строк
0 1 2
10 11 12
неуправляемый двумерный массив int
0 1 2
10 11 12
Приведем еще один пример, в котором сравнивается использование массива массивов (синтаксис [ ] [ ]) и прямоугольного двумерного массива (синтаксис [, ]). На этот раз, ради более корректного сравнения, оба массива содержат элементы типа int.
//Array2.срр
#using <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
void main(void) {
Console::WriteLine("Rectangular array using [,]");
// ("Использование прямоугольного массива [,] ");
int rect2DArray [,] = new int _gc [3,41; // сборщик мусора -
// управляемый
for(int row=0; row< rect2DArray ->GetLength(0); row++) // по строкам {
for(int col=0; col< rect2DArray->GetLength(1); col++)
// по столбцам
{
rect2DArray [row,col] = row*10 + col; // rect2DArray [строка, столбец] = row*10 + столбец; Console : -.Write (rect2DArray [row, col] ) ; // Запись:: (rect2DArray [строка, столбец]); Console::Write("\t"); // Запись }
Console::WriteLine(); }
Console::WriteLine("Array of arrays using [][]"); // ("использование массива массивов [] [] "); int arrayOfArray[3][4]; // неуправляемый for(int row=0; row<3 ; row++) // по строкам {
for(int col=0; col<4; col++) // по столбцам {
arrayOfArray[row][col] = row*10 + col;
Добавлен редактором русского перевода. — Прим. ред.
// arrayOfArray [строка] [столбец] = row*10 + столбец; Console::Write(arrayOfArray[row][col]); // Запись:: (arrayOfArray [строка] [столбец]); Console::Write("\t"); // Запись
}
Console::WriteLine(); } >
Программа напечатает:
Rectangular array using [,]
0 1 2 3
10 11 12 13
20 21 22 23
Array of arrays using [][]
0 1 2 3
10 11 12 13
20 21 22 23
Перевод такой:
Использование прямоугольного массива []
0 1 2 3
10 11 12 13
20 21 22 23
Использование массива массивов [] []
0 1 2 3
10 11 12 13
20 21 22 23
На Рисунок 3.1 и 3.2 показано размещение в памяти элементов массива массивов (объявленного с помощью синтаксиса [ ] [ ]) и прямоугольного двумерного массива (объявленного с помощью синтаксиса [, ]), использовавшихся в предыдущем примере.