Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Управление динамическими массивами как членами класса в Delphi: копирование или передача по ссылке

Delphi , Синтаксис , Массивы

Управление динамическими массивами как членами класса в Delphi

При работе с динамическими массивами в Delphi возникают вопросы о том, как происходит их управление, особенно когда они используются в качестве членов класса. Вопрос заключается в следующем: при передаче динамического массива в метод класса как член, происходит ли его копирование или передача по ссылке? Рассмотрим этот вопрос на примере версии Delphi 10.3.3.

В коде представлены два метода: UpdateArray и UpdateArrayWithParam. Оба метода удаляют первый элемент из массива, но ведут себя по-разному. В методе UpdateArray длина массива остаётся неизменной, в то время как в UpdateArrayWithParam длина корректно уменьшается.

interface

type
  TSomeRec = record
    Name: string;
  end;
  TSomeRecArray = array of TSomeRec;
  TSomeRecUpdate = class
    Arr: TSomeRecArray;
    procedure UpdateArray;
    procedure UpdateArrayWithParam(var ParamArray: TSomeRecArray);
  end;

implementation

procedure TSomeRecUpdate.UpdateArray;
begin
  Delete(Arr, 0, 1);
end;

procedure TSomeRecUpdate.UpdateArrayWithParam(var ParamArray: TSomeRecArray);
begin
  Delete(ParamArray, 0, 1);
end;

procedure Test;
var
  r: TSomeRec;
  lArr: TSomeRecArray;
  recUpdate: TSomeRecUpdate;
begin
  lArr := [];
  r.Name := 'abc';
  lArr := lArr + [r];
  r.Name := 'def';
  lArr := lArr + [r];

  recUpdate := TSomeRecUpdate.Create;
  recUpdate.Arr := lArr;
  recUpdate.UpdateArray;
  // Здесь длина массива не обновляется, остаётся 2.

  // ... (дальше код, демонстрирующий корректное уменьшение длины массива в методе UpdateArrayWithParam)
  recUpdate.Free;
end;

Подтверждённый ответ:

Динамические массивы в Delphi передаются по ссылке. Они управляются компилятором, который использует систему подсчёта ссылок. Документация по структурированным типам в Delphi описывает это поведение.

Однако, после вызова метода UpdateArray, длина массива lArr остаётся равной 2, что может вызвать недоумение. Это происходит из-за процедуры Delete, которая должна перераспределить динамический массив и, следовательно, изменить указатели на него. Однако, Delete знает только об одном из этих указателей — том, который был передан в функцию.

Похоже на то, что после изменения динамического массива в методе UpdateArray, указатель Arr в экземпляре класса TSomeRecUpdate остаётся связанным с изменённым массивом, в то время как исходный массив lArr, с которого была скопирована ссылка, не обновляется.

Альтернативный ответ:

Это интересный вопрос! Процедура Delete изменяет длину динамического массива, как и функция SetLength, и поэтому должна перераспределить динамический массив. Она также изменяет указатель, переданный ей, на новое место в памяти. Однако, она не может изменить другие указатели на старый динамический массив.

Таким образом, ожидается, что старый динамический массив должен иметь уменьшенный счётчик ссылок и быть создан новый динамический массив со счётчиком ссылок 1. Указатель, переданный в Delete, будет установлен на этот новый динамический массив.

Тем не менее, на практике это не всегда происходит. В коде представлен минимальный пример, демонстрирующий неожиданное поведение. После удаления первого элемента из массива, старый массив остаётся изменённым, что может быть интерпретировано как ошибка.

В коде RTL источника Delete сначала пытается уменьшить размер уже выделенной памяти, но затем вызывает функцию DynArraySetLength, которая может создать новый динамический массив, скопировав старый. В результате, исходный массив остаётся изменённым, и новый динамический массив размещается поверх него.

Вывод:

Использование процедуры Delete для динамических массивов может привести к неожиданным результатам, особенно когда эти массивы являются членами класса. Рекомендуется избегать использования Delete в новых проектах и использовать альтернативные методы управления динамическими массивами, такие как SetLength.

Дополнительно, стоит отметить, что в современном коде, написанном в 2020 году, использование Delete не является лучшей практикой, и лучше позволить этой функции устареть.

Создано по материалам из источника по ссылке.

При работе с динамическими массивами в качестве членов класса в Delphi, передача массива методу класса происходит по ссылке, но могут возникать сложности с обновлением длины массива после его изменения в методе из-за особенностей работы с подсчетом ссыло


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Массивы ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-03-14 12:44:03/0.0033788681030273/0