Почему назначение объекта теряется, когда я использую free()?

У меня проблема. Например, когда я пытаюсь получить объект из функции или присвоить.

//Global.-
MyObject:= TMyObject.Create();  
//Local assign.-
myObj:= MyObject;

В приведенном выше случае, если я попробую это:

//Global variable.-
MyObject:= TMyObject.Create();
MyObject.MyData:= 'Salam world';  
//Local variable.-
myObj:= MyObject;
MyObject.Free();
...
ShowMessage(myObj.MyData); //Don't show the data.-

Покажите нарушение прав доступа для этого:

//Global variable.-
MyObject:= TMyObject.Create();
MyObject.MyData:= 'Salam world';
...
//Local variable.-
myObj:= TMyObject.Create();
myObj:= MyObject;
..
MyObject.Free();
...
ShowMessage(myObj.MyData);

Мне нужно освободить глобальную переменную перед локальной переменной. Но я мог бы сохранить копию данных в распределении.

Спасибо за помощь!


person JMCrash    schedule 02.01.2016    source источник
comment
когда вы сделаете это myObj:= MyObject, обе переменные станут одним и тем же объектом. Итак, когда вы вызываете MyObject.Free() после этого, переменная myObj также освобождается. Итак, я не могу понять, почему вы пытаетесь освободить объект MyObject, если хотите использовать его данные дальше в коде?   -  person ankhzet    schedule 02.01.2016
comment
Зачем вам две переменные?   -  person David Heffernan    schedule 02.01.2016


Ответы (2)


Вы не можете освободить переменную, вы можете только освободить/уничтожить объект.

Итак, когда в вашем коде вы вызываете

MyObject.Free();

На самом деле вы уничтожаете объект, на который ссылается переменная MyObject. И это тот же объект, на который ссылается/указывает ваша переменная myObj.

И причина, по которой они оба указывают на один и тот же объект, заключается в том, что когда вы вызывали

myObj:= MyObject;

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

Вы видите, что в Delphi/Object Pascal есть два типа переменных. Ссылочные и нессылочные переменные.

Переменные без ссылок — это простые переменные, например, целые числа. Они прямо указывают на область памяти, содержащую их данные. И их размер точно такой же, как размер блока памяти, на который они указывают.

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

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

Но их главный недостаток заключается в том, что вам нужен надлежащий механизм, чтобы убедиться, что память, содержащая объект, на который они ссылаются, освобождается в нужное время. Вот почему вам нужно вызвать MyObject.Free или MyObject.Destroy, чтобы эта память была освобождена.

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

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

Я предполагаю, что есть две возможные причины этого:

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

MyGlobalObject := SomeNewObject;

or

MyGlobalObject := TSomeObject.Create;

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

MyGlobalObject := nil;

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

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

person SilverWarior    schedule 02.01.2016
comment
в Delphi/Object Pascal есть два типа переменных. Ссылочные и нессылочные переменные. На самом деле следует сказать: в Delphi/Object Pascal есть ссылочные типы и типы значений. - person Stefan Glienke; 04.01.2016
comment
@StefanGlienke Строго следуя официальной терминологии, да. Но строгая замена того, что я сказал, тем, что вы предлагаете, вероятно, еще больше запутает ОП. Особенно, если он не понимает базового определения переменной и того, как тип переменной влияет на то, как ей присваиваются данные. Поэтому я решил пропустить использование официальной терминологии и вместо этого использовать описательную терминологию, чтобы помочь ОП понять, что я пытаюсь ему сказать. И основываясь на том факте, что ОП отметил мой ответ как правильный, даже если он ранее отметил ответ Кена Уайта как правильный, я думаю, мне это удалось. - person SilverWarior; 04.01.2016

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

//Global variable.-
MyObject:= TMyObject.Create();
MyObject.MyData:= 'Salam world';  

Следующая строка не создает вторую копию объекта. Это просто заставляет myObj также указывать на MyObject.

//Local variable.-
myObj:= MyObject;

Вы можете убедиться в этом сами, используя следующий код:

MyObject := TMyObject.Create;
MyObject.MyData := 'Some text';
ShowMessage(MyObject.MyData);      // Shows 'Some text'

myObj := MyObject;
// Change local variable property value
myObj.MyData := 'Different text';
// Display global variable property value
ShowMessage(MyObject.MyData);     // Shows 'Different text'

Эта строка освобождает MyObject, а это означает, что myObj теперь ссылается на объект, который вы только что освободили, поскольку он просто указывает на содержимое MyObject.

MyObject.Free();

Если вы хотите сделать копию, используйте вместо этого Assign.

myObj := TMyObject.Create;
myObj.Assign(MyObject);
person Ken White    schedule 02.01.2016
comment
Стоит отметить, что в ваших собственных классах вы должны реализовать метод Assign самостоятельно, реализация по умолчанию в TPersistent вызывает AssignTo источника, который, вероятно, также не реализован, поэтому вы получите исключение. - person Yuriy Afanasenkov; 02.01.2016