Может ли пропуск "^" при доступе к членам указателя записи вызвать нарушение прав доступа? - PullRequest
0 голосов
/ 28 марта 2011

В VirtualTreeview я храню свои данные в PVirtualNodes . Я столкнулся с несколькими нарушениями прав доступа (как правило, с "Чтение адреса 00000000" ) в моем приложении, и они в основном (я бы даже осмелился сказать Всегда) происходят, когда я что-то делаю с моими данными узла.

Однако дело в том, что я заявляю свои вещи и использую их так:

// DUMMY CODE - Not written or tested in IDE
var
 MyNode : PVirtualNode;
 MyData : PMyNodeData;
Begin
 MyNode := VST.GetFirstSelected;

 if Assigned(MyNode) then
  Begin
   MyData := VST.GetNodeData(MyNode);
   if Assigned(MyData) then
   Begin
     MyData.DummyProperty := 'Test';
   End;
  End;
End;

Как вы, наверное, заметили, я не "разыменование" (правильно?) Мои "MyData" , выполняя MyData ^ ! Причина, по которой я этого не делаю, заключается в том, что мне сказали, что нет необходимости добавлять каретку к имени указателя, однако я чувствую, что это как-то связано с этим. Если бы я знал, я бы не писал здесь. ;)

Итак, мой вопрос: в конце концов, необходимо ли добавить маленький ^ к MyData? И возможно ли, что не сделав этого, я могу спровоцировать нарушение доступа?

Ответы [ 3 ]

4 голосов
/ 28 марта 2011

Если у вас есть указатель на запись, вы можете опустить ^.Следующие значения эквивалентны:

MyData.DummyProperty
MyData^.DummyProperty

Это также относится к устаревшему Turbo Pascal object.Я ожидаю, что так будет и с классами Delphi, хотя я никогда не пробовал использовать их, поскольку они уже являются ссылочными типами.

К сожалению, это не объяснение для вашего AV.

2 голосов
/ 28 марта 2011

Использование ^ для разыменования записей является необязательным, так как это неявно предполагается компилятором.Если не использовать какую-либо жесткую типизацию, любая ситуация, для которой требуется «^», не будет компилироваться.Но только 1 уровень разыменования является неявным.

type
  TMyRecord  = record
    MyField : Integer;
  end;
  PMyRecord = ^TMyRecord;
  PPMyRecord = ^PMyRecord;

procedure DoSomething;
var vMyField : PPMyRecord;
begin
  vMyField.MyField;  <---Won't compile
  vMyField^.MyField; <---Will compile
end;

Что касается вашего нарушения доступа, вот мое лучшее предположение, основанное на том, что вы написали ... Предполагая, что ваш пример является репрезентативным (то есть, сбой при назначениистрока), и предполагая, что PMyNodeData указывает на запись.Я полагаю, что память PMyNodeData была зарезервирована с «GetMem» вместо «New», что делает поле строки записи неинициализированным.

1 голос
/ 29 марта 2011

Исключение составляют Data.xx и Data^.xx, которые не совпадают: поле, на которое указывает поле, имеет одинаковый тип указателя или общий тип указателя:

var
  x: PPointer;
  y: Pointer;
begin
  x := GetPPointer();
  y := x;
  y := x^;
end;

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

Учитывая ваш пример: возможно, проблема в повреждении памяти. Вы правильно установили NodeDataSize?

...