Когда вы вызываете AddChild(..., @TestArray[0])
, вы инициализируете только первые четыре байта данных узла.Это поле Text
.Поле Text
содержит указатель на структуру TTest
. предполагается для хранения ссылки string
.
Функция GetNodeData
возвращает указатель на данные узла.Элемент управления дерева выделил запись TVirtualNode
, и сразу после этого в последовательной памяти он выделил для использования NodeDataSize
байт, а GetNodeData
возвращает адрес этого пространства.Вы должны рассматривать это как указатель на структуру TTest
.И вы делаете, для некоторого вашего кода.Похоже, вы пытаетесь обойти ограничение, что только первые четыре байта структуры инициализируются при вызове AddChild
.(Я не могу сказать, что рекомендую это. Существуют и другие способы связать данные с узлом, которые не требуют такого большого количества типов.)
Вы правильно назначаете Data
для способа, которым данные узладолжен быть использован.Вы правильно присваиваете NodeData
для того, что действительно хранит во время инициализации - указатель на указатель на структуру TTest
.Вы правильно разыменовываете NodeData
для чтения поля Number
, и вы также читаете поля Text
правильно.Однако поле Data.Text
нельзя перезаписать так, как оно есть:
Data.Text := PTest(NodeData^)^.Text;
Поле Data.Text
в настоящее время не содержит действительного значения string
, но переменные string
требуется для постоянного хранения допустимых значений (или, по крайней мере, всегда, когда есть вероятность, что они будут прочитаны или записаны).Чтобы назначить переменную string
, программа увеличивает счетчик ссылок на новое значение и уменьшает счетчик ссылок на старое, но, поскольку «старое значение» в этом случае на самом деле не является string
, нет действительногоколичество ссылок на декремент, и даже если бы они были, память в этом месте все равно не могла быть освобождена - она принадлежит TestArray
.
Хотя есть способ обойти это.Скопируйте строку в два этапа.Сначала прочитайте значение из NodeData.Text
в резервную переменную string
.Как только вы это сделаете, вам больше не понадобится NodeData
, поэтому вы можете перезаписать значение, на которое оно указывает.Если вы установите его равным all-bits-zero, то вы также неявно перезапишете Data.Text
со значением пустой строки.На этом этапе можно перезаписать как string
переменную :
tmp := PTest(NodeData^)^.Text;
PTest(NodeData^) := nil;
Data.Text := tmp;
Другой способ обойти это - изменить порядок полей в данных узла.Сначала укажите поле Integer
, а вместо Data.Text
инициализируйте Data.Number
последним.Integer
значения всегда можно перезаписать, независимо от их содержимого.
Что бы вы ни делали, убедитесь, что вы завершили запись в событии OnFreeNode
:
var
Data: PTest;
begin
Data := Sender.GetNodeData;
Finalize(Data^);
end;
Это гарантирует, что поле string
при необходимости уменьшит количество ссылок.