Информация об изменениях

Сообщение Re[3]: Ну спасибо за развёрнутый ответ.. от 16.10.2019 12:24

Изменено 16.10.2019 13:29 alexzzzz

Re[3]: Ну спасибо за развёрнутый ответ..
Здравствуйте, nt2000, Вы писали:

A>>или нужно получить новое значение value-типа, через конструктор этого типа:

A>>
DateTime dateTime = new DateTime(...);


N>Интересно чисто для самообразования..

N>Если переменные ради значений порождают огромные махины — классы, потом после получения желанных значений куда деваются эти классы? болтаются как бедные родственники никому не нужные? а если переменная захочет получить другие значения, то надо рожать опять новый экземпляр?

Сначала немножко про терминологию.

Есть ссылочные типы: классы, интерфейсы, делегаты, строки, массивы. Переменная ссылочного типа хранит ссылку (грубо говоря, указатель) на объект (по-другому экземпляр) этого типа, расположенный в куче (обычно). А объект/экземпляр в свою очередь хранит в себе полезные и некоторые служебные данные. Т.е. слово класс обозначает какой-то ссылочный тип, а объект или экземпляр класса ― это та штука, в которой хранятся данные этого типа.

Есть value-типы: структуры, перечисления (enum) и все встроенные числовые и логические типы (int, float, bool...). Переменная value-типа хранит непосредственно данные.

Есть ещё отдельно указатели, но хрен с ними.

Согласно спецификации, значением переменной ссылочного типа является ссылка на объект (который где-то там лежит и что-то хранит), значением переменной value-типа являются непосредственно сами данные этого типа.

--
DateTime dateTime = new DateTime(...);

Оператор new нестрашный. В случае value-типов, а DateTime — это структура, value-тип, new просто обозначает вызов конструктора. Никакого объекта где-то в куче не создаётся, просто выделяется место на стеке (если переменная локальная) и вызывается конструктор, который заполняет это место правильными данными. Если переменная сильно временная и помещается в регистр процессора, то и место в стеке может не выделяться — это на усмотрение jit-компилятора.

struct Vector2
{
    public float x, y;

    public Vector2(float x, float y)
    {
        this.x = x;
        this.y = y;
    }

    public void Initialize(float x, float y)
    {
        this.x = x;
        this.y = y;
    }
}


Что мы напишем
var v = new Vector2(1, 2);

что
Vector2 v = new Vector2();
v.Initialize(1, 2);
что
Vector2 v = default;
v.Initialize(1, 2);

что
Vector2 v;
v.x = 1;
v.y = 2;

никакой разницы не будет. Разве что конкретный JIT-компилятор в конкретных условиях может заинлайнить вызов функции, а может не заинлайнить. Разницы по потреблению памяти точно не будет.

Если тип ссылочный, например строка:
var s = new string('X', 3);

оператор new создаёт в куче экземпляр данного типа и вызывает его конструктор с заданными параметрами, который заполняет экземпляр типа нужными данными. На выходе получаем ссылку на этот экземпляр, которая потом сохраняется в переменную s.

Да, мы создали в куче новый объект, но это никакой не лишний промежуточный объект, а тот самый объект, ссылка на который в итоге будет храниться в переменной s.

Если переменной s позже изменить значение ― присвоить ссылку на другой объект, то наш первый объект, если на него больше никто не ссылается, будет сожран сборщиком мусора, если сборщик мусора этого захочет.
Re[3]: Ну спасибо за развёрнутый ответ..
Здравствуйте, nt2000, Вы писали:

A>>или нужно получить новое значение value-типа, через конструктор этого типа:

A>>
DateTime dateTime = new DateTime(...);


N>Интересно чисто для самообразования..

N>Если переменные ради значений порождают огромные махины — классы, потом после получения желанных значений куда деваются эти классы? болтаются как бедные родственники никому не нужные? а если переменная захочет получить другие значения, то надо рожать опять новый экземпляр?

Сначала немножко про терминологию.

Есть ссылочные типы: классы, интерфейсы, делегаты, строки, массивы. Переменная ссылочного типа хранит ссылку (грубо говоря, указатель) на объект (по-другому экземпляр) этого типа, расположенный в куче (обычно). А объект/экземпляр в свою очередь хранит в себе полезные и некоторые служебные данные. Т.е. слово класс обозначает какой-то ссылочный тип, а объект или экземпляр класса ― это та штука, в которой хранятся данные этого типа.

Есть value-типы: структуры, перечисления (enum) и все встроенные числовые и логические типы (int, float, bool...). Переменная value-типа хранит непосредственно данные.

Есть ещё отдельно указатели, но хрен с ними.

Согласно спецификации, значением переменной ссылочного типа является ссылка на объект (который где-то там лежит и что-то хранит) или null, значением переменной value-типа являются непосредственно сами данные этого типа.

--
DateTime dateTime = new DateTime(...);

Оператор new нестрашный. В случае value-типов, а DateTime — это структура, value-тип, new просто обозначает вызов конструктора. Никакого объекта где-то в куче не создаётся, просто выделяется место на стеке (если переменная локальная) и вызывается конструктор, который заполняет это место правильными данными. Если переменная сильно временная и помещается в регистр процессора, то и место в стеке может не выделяться — это на усмотрение jit-компилятора.

struct Vector2
{
    public float x, y;

    public Vector2(float x, float y)
    {
        this.x = x;
        this.y = y;
    }

    public void Initialize(float x, float y)
    {
        this.x = x;
        this.y = y;
    }
}


Что мы напишем
var v = new Vector2(1, 2);

что
Vector2 v = new Vector2();
v.Initialize(1, 2);
что
Vector2 v = default;
v.Initialize(1, 2);

что
Vector2 v;
v.x = 1;
v.y = 2;

никакой разницы не будет. Разве что конкретный JIT-компилятор в конкретных условиях может заинлайнить вызов функции, а может не заинлайнить. Разницы по потреблению памяти точно не будет.

Если тип ссылочный, например строка:
var s = new string('X', 3);

оператор new создаёт в куче экземпляр данного типа и вызывает его конструктор с заданными параметрами, который заполняет экземпляр типа нужными данными. На выходе получаем ссылку на этот экземпляр, которая потом сохраняется в переменную s.

Да, мы создали в куче новый объект, но это никакой не лишний промежуточный объект, а тот самый объект, ссылка на который в итоге будет храниться в переменной s.

Если переменной s позже изменить значение ― присвоить ссылку на другой объект, то наш первый объект, если на него больше никто не ссылается, будет сожран сборщиком мусора, если сборщик мусора этого захочет.