Вопрос

несколько вопросов о записях в Delphi:

  1. Поскольку записи почти как классы, почему бы не использовать только классы вместо записей?
  2. Теоретически, память выделяется для записи, когда она объявлена переменной;но, а как освобождается память после этого?
  3. Я могу понять полезность указателей на записи в объект списка, но с универсальными контейнерами (TList<T>), нужно ли еще использовать указатель?если нет, то как удалить / освободить каждую запись в общий контейнер?Если я хочу удалить определенную запись в общий контейнер, как это сделать?
Это было полезно?

Решение

Для 1 и 2:записи - это типы значений, в то время как классы - это ссылочные типы.Они размещаются в стеке или непосредственно в пространстве памяти любой переменной большего размера, которая их содержит, а не через указатель, и автоматически очищаются компилятором, когда они выходят за пределы области видимости.

Что касается вашего третьего вопроса, то TList<TMyRecord> внутренне объявляет array of TMyRecord для места для хранения.Все записи в нем будут очищены, когда список будет уничтожен.Если вы хотите удалить определенный файл, используйте Delete метод удаления по индексу, или Remove способ поиска и удаления.Но имейте в виду, что, поскольку это тип значения, все, что вы делаете, будет заключаться в создании копий записи, а не в копировании ссылок на нее.

Другие советы

Существует много различий между записями и классами;и никакого "Указателя на запись". <> "Класс".У каждого из них есть свои плюсы и минусы;одна из важных вещей в разработке программного обеспечения - понимать их, чтобы вам было легче выбрать наиболее подходящее для данной ситуации.

  1. Этот вопрос основан на ложной посылке.Записи почти не похожи на классы, точно так же, как целые числа почти не похожи на Двойные.
    • Классы всегда должны создаваться динамически, тогда как это возможно, но не является обязательным требованием для записей.
    • Экземпляры классов (которые мы называем объектами) всегда передаются по ссылке, что означает, что несколько разделов кода будут совместно использоваться в одном и том же экземпляре.Это важно помнить, потому что вы можете непреднамеренно изменить объект в качестве побочного эффекта;хотя, когда это сделано намеренно, это мощная функция.Записи, с другой стороны, передаются по значению;вам нужно явно указать, передаете ли вы их по ссылке.
    • Классы "копируются не так легко, как записи".Когда я говорю копировать, я имею в виду отдельный экземпляр, дублирующий исходный код.(Это должно быть очевидно в свете приведенного выше комментария о значении / ссылке).
    • Записи, как правило, очень хорошо работают с типизированными файлами (потому что их так легко скопировать).
    • Записи могут накладывать поля друг на друга (случай x из /unions).
    • Это были комментарии по поводу определенных ситуационных преимуществ записей;и наоборот, существуют также ситуационные преимущества для занятий, на которых я не буду подробно останавливаться.
  2. Возможно, самый простой способ понять это - быть немного педантичным в этом вопросе.Давайте внесем ясность;память на самом деле не выделяется "при ее объявлении", она выделяется, когда переменная находится в области видимости, и освобождается, когда она выходит за пределы области видимости.Таким образом, для локальной переменной она выделяется непосредственно перед началом процедуры и освобождается сразу после окончания.Что касается поля класса, то оно выделяется при создании объекта и освобождается при его уничтожении.
  3. Опять же, есть свои плюсы и минусы...
    • Это может быть медленнее и требовать больше памяти для копирования целых записей (как в случае с дженериками), чем для простого копирования ссылок.
    • Передача записей по ссылкам (с использованием указателей) - это мощный метод, с помощью которого вы можете легко заставить что-то другое изменить вашу копию записи.Без этого вам пришлось бы передавать свою запись по значению (т.е.скопируйте его) получите в результате измененную запись, скопируйте ее снова в свои собственные структуры.
  4. Являются ли указатели на записи подобными классам?Нет, вовсе нет.Всего лишь два отличия:
    • Классы поддерживают полиморфное наследование.
    • Классы могут реализовывать интерфейсы.

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

Было проделано много работы по повышению скорости выделения памяти, чтобы улучшить скорость работы со строками и объектами, но это никогда не будет так быстро, как замена 100 000 выделений памяти на 1 выделение памяти.

Однако, если вы используете массив записей, не копируйте запись в локальные переменные.Это может легко свести на нет преимущество в скорости.

Есть несколько других различий между классом и записью.Классы могут использовать полиморфизм, и раскрывать интерфейсы.Записи не могут реализовывать деструкторы (хотя, начиная с Delphi 2006, теперь они могут реализовывать конструкторы и методы).

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

1) Чтобы обеспечить наследование и полиморфизм, классы имеют некоторые накладные расходы.Записи не допускают этого, и в некоторых ситуациях это может быть несколько быстрее и проще в использовании.В отличие от классов, которые всегда размещаются в куче и управляются с помощью ссылок, записи также могут быть размещены в стеке, доступны напрямую и назначены друг другу без необходимости вызова метода "Assign".Также записи полезны для доступа к блокам памяти с заданной структурой, потому что их расположение в памяти точно такое, как вы его определяете.Расположение памяти экземпляра класса контролируется компилятором и содержит дополнительные данные для обеспечения работы объектов (т. е.указатель на таблицу виртуальных методов).

2) Если вы не выделяете записи динамически, используя New() или GetMem() , память записей управляется компилятором в виде ординалов, плавающих значений или статических массивов:память глобальных переменных выделяется при запуске и освобождается при завершении работы программы, а локальные переменные выделяются в стеке при входе в функцию / процедуру / метод и освобождаются при выходе.Выделение / освобождение памяти в стеке происходит быстрее, потому что для этого не требуются вызовы диспетчера памяти, просто очень мало инструкций ассемблера для изменения регистров стека.Но имейте в виду, что выделение большой структуры в стеке может вызвать переполнение стека, поскольку максимальный размер стека фиксирован и не очень велик (см. Параметры компоновщика).Если записи являются полями класса, они выделяются при создании класса и освобождаются при освобождении класса.

3) Одно из преимуществ дженериков заключается в устранении необходимости низкоуровневого управления указателями, но будьте в курсе внутренней работы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top