Жизненный цикл объекта: различия между версиями

Материал из wikiru.visual-prolog.com

(Новая: ==Создание объекта== Других способов создания объектов (экземпляров), кроме как с использованием преди...)
 
Строка 51: Строка 51:
     вызовПредикатаДругогоКлоза(МойОбъект),     
     вызовПредикатаДругогоКлоза(МойОбъект),     
     ...
     ...
     последнийПредикатКлоза(...).<vip>
     последнийПредикатКлоза(...).</vip>
время жизни объекта продлевается за пределы времени жизни клоза. Объект будет существовать все то время, пока на него существует указатель.
время жизни объекта продлевается за пределы времени жизни клоза. Объект будет существовать все то время, пока на него существует указатель.
Когда объект больше не нужен, достаточно удалить ссылку на него, например так:
Когда объект больше не нужен, достаточно удалить ссылку на него, например так:
Строка 75: Строка 75:
Это значит, что практически возможно вместо
Это значит, что практически возможно вместо
<vip>facts
<vip>facts
мойУказатель_V:мойИнтерфейс:=erroneous.<vip>
мойУказатель_V:мойИнтерфейс:=erroneous.</vip>
объявлять
объявлять
<vip>facts
<vip>facts
мойУказатель_V:object:=erroneous.<vip>
мойУказатель_V:object:=erroneous.</vip>
При этом будет компилироваться и работать
При этом будет компилироваться и работать
<vip>clauses
<vip>clauses
   мойПример():-
   мойПример():-
     мойУказатель_V:=мойОбъект::new(),
     мойУказатель_V:=мойОбъект::new(),
     ...<vip>
     ...</vip>
Но вот вызов
Но вот вызов
<vip>    ...
<vip>    ...
     мойУказатель_V:мойПредикатИзМойОбъект(...),
     мойУказатель_V:мойПредикатИзМойОбъект(...),
     ...<vip>
     ...</vip>
в этом случае не пропустит компилятор.
в этом случае не пропустит компилятор.
Вместо этого необходимо призводить конвертацию
Вместо этого необходимо призводить конвертацию
Строка 93: Строка 93:
     МойУказатель=convert(мойИнтерфейс,мойУказатель_V),
     МойУказатель=convert(мойИнтерфейс,мойУказатель_V),
     МойУказатель:мойПредикатИзМойОбъект(...),
     МойУказатель:мойПредикатИзМойОбъект(...),
     ...<vip>
     ...</vip>
Примерно то же происходит, если интерфейс поддерживает другие интерфейсы.
Примерно то же происходит, если интерфейс поддерживает другие интерфейсы.
Сборщик мусора можно подтолкнуть предикатом  
Сборщик мусора можно подтолкнуть предикатом  
<vip>memory::garbageCollect()<vip>
<vip>memory::garbageCollect()</vip>


Следует иметь в виду, что момент, когда память будет фактически освобождена, не контролируется и определяется внутренней логикой сборщика мусора и его взаимодействием с операционной системой. [[Категория:VipLanguage]]
Следует иметь в виду, что момент, когда память будет фактически освобождена, не контролируется и определяется внутренней логикой сборщика мусора и его взаимодействием с операционной системой. [[Категория:VipLanguage]]

Версия 10:11, 19 сентября 2007

Создание объекта

Других способов создания объектов (экземпляров), кроме как с использованием предикатов, объявленных для данного класса конструктором, нет. Если конструктор не объявлен, то может быть использован предопределенный конструктор new().

Гибель объекта

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

clauses
  мойПример():-
     МойОбъект=мойОбъект::new(),
     МойОбъект:мойПредикатИзМойОбъект(...),
     ...
     последнийПредикатКлоза(...).

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

clauses
  мойПример():-
     МойОбъект=мойОбъект::new(),
     МойОбъект:мойПредикатИзМойОбъект(...),
     ...
     вызовПредикатаДругогоКлоза(МойОбъект),    
     ...
     последнийПредикатКлоза(...).

не меняет сути - пока выполняется предикат вызовПредикатаДругогоКлоза(МойОбъект) экземпляр продолжает жить и умрет после завершения выполнения предиката последнийПредикатКлоза(...).

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

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

Поэтому имя интерфейса используется в качестве домена при декларировании фактов для хранения указателей или их передачи в качестве параметров. Например,

class мойКласс:мойИнтерфейс
end classмойКласс

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

facts
мойУказатель_F:(string УдобноеИмяЭкземпляра,мойИнтерфейс УказательНаЭкземпляр).

либо в виде

facts
мойУказатель_V:мойИнтерфейс:=erroneous.<vip>
Являются правильными (не путать с целесообразностью) объявлениями.
Тогда в примере
<vip>clauses
  мойПример():-
     МойОбъект=мойОбъект::new(),
     МойОбъект:мойПредикатИзМойОбъект(...),
     мойУказатель_V:=МойОбъект,
     ...
     вызовПредикатаДругогоКлоза(МойОбъект),    
     ...
     последнийПредикатКлоза(...).

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

     ...
     мойУказатель_V:=erroneous,
     ...

или так

     ...
     retract(мойУказатель_F("ПочтовыеАдреса",_УказательНаЭкземпляр)),
     ...

При этом следует иметь в виду, что смерть объекта ведет к смерти всех объектов, на которые данный объект хранит ссылки.

Тогда, например, если имеется дерево, построенное на основе ссылок на объекты, то потеря указателя на корень дерева ведет к смерти всех объектов, входящих в дерево.

Следует, однако, иметь в виду некоторые исключения из этого правила: Как показал опыт, если объект хранит указатель на окно (домен vpiDomains::windowHandle), то сборщик мусора будет рассматривать этот объект, как используемый.

То есть физически окно может быть закрыто, но неудаление указателя на это окно оставит объект в памяти. Аналогично часто указатели на COM-объекты могут быть причиной неособождения памяти сборщиком мусора.

Существует один замечательный предопределенный домен, применительно к зкземплярам. Это домен - object.

Все экземпляры, принадлежа доменам своих интерфейсов, в то же время являются дочерними доменами домена object. Это значит, что практически возможно вместо

facts
мойУказатель_V:мойИнтерфейс:=erroneous.

объявлять

facts
мойУказатель_V:object:=erroneous.

При этом будет компилироваться и работать

clauses
  мойПример():-
     мойУказатель_V:=мойОбъект::new(),
     ...

Но вот вызов

     ...
     мойУказатель_V:мойПредикатИзМойОбъект(...),
     ...

в этом случае не пропустит компилятор. Вместо этого необходимо призводить конвертацию

     ...
     МойУказатель=convert(мойИнтерфейс,мойУказатель_V),
     МойУказатель:мойПредикатИзМойОбъект(...),
     ...

Примерно то же происходит, если интерфейс поддерживает другие интерфейсы. Сборщик мусора можно подтолкнуть предикатом

memory::garbageCollect()

Следует иметь в виду, что момент, когда память будет фактически освобождена, не контролируется и определяется внутренней логикой сборщика мусора и его взаимодействием с операционной системой.