Динамическое выделение памяти. Оператор new. Выделение памяти для типов-значений, структур, перечислений, объектов классов. Выделение памяти для массивов

Динамическое выделение памяти. Оператор new. Выделение памяти для типов-значений, структур, перечислений, объектов классов. Выделение памяти для массивов


Содержание



1. Как в C# реализуется динамическое выделение памяти? Назначение оператора new. Общая форма

В программах на C# память для объектов нужно выделять динамически. Динамическое выделение памяти для объектов или других видов данных реализуется с помощью оператора new. Общая форма оператора new

new ClassName(parameters_list)

где

  • ClassName – имя класса, для объекта которого выделяется память;
  • parameter_list – список параметров, которые принимает один из конструкторов класса. Обязательно, в классе должен быть реализован конструктор, параметры которого совпадают с parameter_list. Конструктор может быть без параметров (конструктор по умолчанию).

 

2. Выделение памяти оператором new для массива объектов. Общая форма

Общая форма выделения памяти для массива объектов, который есть экземпляром класса ClassName, имеет вид:

new ClassName[size]

где

  • ClassName – имя класса, который есть базовым типом для массива объектов (экземпляров);
  • size – размерность массива.

После выделения памяти для массива объектов нужно выделить память для любого объекта класса. В другом случае возникнет критическая ситуация с сообщением

Object reference not set to an instance of an object
Ссылка на объект не установлена на экземпляр объекта

 

3. Пример выделения памяти для одиночного объекта класса

Пусть задан класс, описывающий общие сведения о стране. Объявление класса имеет следующий вид:

// класс, который описывает общую информацию о стране
class Country
{
    string name; // название страны
    ulong population; // население
    double square; // площадь
    string capital; // столица

    // конструкторы класса
    // конструктор без параметров
    public Country()
    {
        name = "";
        population = 0;
        square = 0.0;
        capital = "";
    }

    // конструктор с 4 параметрами
    public Country(string _name, ulong _population, double _square, string _capital)
    {
        name = _name;
        population = _population;
        square = _square;
        capital = _capital;
    }

    // методы доступа
    public void Set(string _name, ulong _population, double _square, string _capital)
    {
        name = _name;
        population = _population;
        square = _square;
        capital = _capital;
    }

    public void Get(out string _name, out ulong _population, out double _square, out string _capital)
    {
        _name = name;
        _population = population;
        _square = square;
        _capital = capital;
    }
}

Тогда выделение памяти для класса и его использование может быть примерно следующим

// использование класса Country

// выделение памяти - вызывается конструктор без параметров
Country c1 = new Country();

// выделение памяти с инициализацией конструктором с 4 параметрами
Country c2;
c2 = new Country("Namibia", 2358163, 825418, "Windhoek");

// использование методов класса c2
string name, cap;
double square;
ulong popul;

c2.Get(out name, out popul, out square, out cap);
// name = "Namibia", popul = 2358163, square = 825418, cap = "Windhoek"

При использовании оператора new вызывается соответствующий конструктор класса. Если в классе не реализован ни один конструктор, то вызывается конструктор по умолчанию, который не имеет параметров.

 

4. Пример выделения памяти для массива объектов (экземпляров) класса

Память для массива объектов некоторого класса выделяется в 2 этапа. Сначала выделяется память для массива ссылок на экземпляры класса. Затем, в цикле, выделяется память для любого объекта (экземпляра) класса.

Пример. Пусть задан класс MyClass.

// класс MyClass
class MyClass
{
    public int d; // внутренняя переменная класса
}

В нижеследующем программном коде выделяется память для массива объектов типа MyClass. Затем выделяется память для любого экземпляра (объекта) класса.

...

MyClass[] mc = new MyClass[10]; // выделение памяти для массива в целом

// выделение памяти для любого объекта
for (int i = 0; i < 10; i++)
    mcA[i] = new MyClass();

// заполнение массива mc квадратами чисел от 0 до 9
for (int i = 0; i < 10; i++)
    mcA[i].d = i * i;

...

 

5. Пример выделения памяти для структуры

Пусть задана структура Date, которая реализует дату

// структура, которая описывает дату
struct Date
{
    int day;
    int month;
    int year;

    // конструктор структуры
    public Date(int day, int month, int year)
    {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    // метод, который возвращает значение полей day, month, year
    public void Get(out int d, out int m, out int y)
    {
        d = day;
        m = month;
        y = year;
    }
}

Выделение памяти для структурной переменной с именем dt и использование структурной переменной имеет вид:

Date dt = new Date(11, 05, 2008); // выделение памяти для структурной переменной

int d, m, y;
dt.Get(out d, out m, out y); // взять день недели: d=11, m=5, y=2008

 

6. Пример выделения памяти для массива структур

Выделение памяти для массива структур реализуется в два этапа. Сначала выделяется память для массива переменных (ссылок). Затем выделяется память для каждого элемента массива (каждой структурной переменной).

Пусть задана структура Worker, которая реализует данные о работнике:

// структура, описывающая данные о работнике
struct Worker
{
    public string name; // Фамилия и имя работника
    public int age; // возраст работника
    public float rank; // рейтинг работника
}

Демонстрация использования массива структур Worker:

Worker[] W; // объявление переменной W типа массив структур Worker

W = new Worker[20]; // выделение памяти для массива ссылок (объектов) на структуры

// Выделение памяти для любого объекта структуры - обязательно
for (int i = 0; i < W.Length; i++)
    W[i] = new Worker();

// Заполнение массива W значениями
for (int i=0; i<W.Length; i++)
{
    W[i].name = "";
    W[i].age = 100;
    W[i].rank = 1.0f;
}

 

7. Пример выделения памяти для перечисления

Задано перечисления DayWeek

// перечисление DayWeek
enum DayWeek
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

Выделение памяти для переменной типа перечисление DayWeek и ее использование может быть таким:

DayWeek dw = new DayWeek();
dw = DayWeek.Monday;
int d = (int)dw; // d = 0

dw = DayWeek.Thursday;
d = (int)dw; // d = 3

 

8. Выделение памяти для типов-значений. Примеры

Оператор new может выделять память для типов значений, таких как int, double и т.д. В этом случае вызывается конструктор, инициализирующий переменную нулевым значением. Вызов оператора new для любого типа-значения приводит к вызову конструктора по умолчанию для данного типа.

Пример 1. Выделение памяти для одиночных типов-значений.

// выделение памяти для типов-значений
int i = new int();
double d = new double();
bool b = new bool();

i = 23;
d = 7.323;
b = false;

Пример 2. Выделение памяти для массивов типов-значений.
В примере выделяется память для массива из 20 чисел типа int и массива из 30 чисел типа double.

// выделение памяти для массивов типов-значений
int[] A = new int[20]; // массив из 20 целых чисел
double[] B = new double[30]; // массив из 30 чисел типа double

// заполнение массивов значениями
for (int j = 0; j < A.Length; j++)
    A[j] = j * j + 2;

for (int j = 0; j < B.Length; j++)
    B[j] = 0.5 * j + 1;

Как видно из примера, не нужно выделять память для каждого элемента массива как это делается в случае с массивами объектов. Однако, по желанию можно выделить как показано ниже.

// выделение памяти для каждого элемента массива A
for (int j = 0; j < A.Length; j++)
    A[j] = new int();

 


Связанные темы