OberonCore
https://forum.oberoncore.ru/

NEW в процедуре.
https://forum.oberoncore.ru/viewtopic.php?f=29&t=5881
Страница 1 из 2

Автор:  prospero78 [ Пятница, 02 Сентябрь, 2016 17:35 ]
Заголовок сообщения:  NEW в процедуре.

Уважаемые коллеги!
Совершенно очевидно, что я не понимаю, как работает такой кусок:
1. Создаю статический указатель на запись.
2. Передаю в процедуру этот указатель, где в процедуре делаю NEW(указатель) и все остальные первоначальные манипуляции.
3. При возврате из процедуры BlackBox ругается на NIL. Т.е. фактически, как мой указатель был инициирован NIL, так и остался.

Подскажите правильный порядок действий. Если это возможно.
Может, как-то разыменование сделать. Или RETURN с указателем через локальный VAR (хотя, на сколько я понимаю, такой указатель будет на стеке?)

Короче, надеюсь только на вас))

Автор:  Александр Ильин [ Пятница, 02 Сентябрь, 2016 17:48 ]
Заголовок сообщения:  Re: NEW в процедуре.

Код в студию!

Не понятно, что такое "статический указатель".
Не понятно, передаётся ли указатель в процедуру по ссылке или по значению.

Автор:  prospero78 [ Пятница, 02 Сентябрь, 2016 18:12 ]
Заголовок сообщения:  Re: NEW в процедуре.

Примерно так:
Код:
MODULE a1
TYPE
 tpRecord = POINTER TO RECORD
    a:BYTE
  END;

PROCEDURE Init*(tpr_:tpRecord; a_:BYTE);
BEGIN
  NEW(tpr_);
  tpr_.a:=a_
END Init;

END a1.


Код:
MODULE a2;
IMPORT a1;
VAR
    myVar: a1.tpRecord;

BEGIN
  a1.Init(myVar,0)
END a1.


Подозреваю, что где-то что-то я забыл)) Подставить VAR перед указателем в процедуре?

Автор:  Alexander Shiryaev [ Пятница, 02 Сентябрь, 2016 18:20 ]
Заголовок сообщения:  Re: NEW в процедуре.

да

Автор:  prospero78 [ Пятница, 02 Сентябрь, 2016 18:33 ]
Заголовок сообщения:  Re: NEW в процедуре.

Хорошо. Вопрос в догонку. Я наследую через указатель -- указатель на расширяемую запись.
1. Так можно?
2. Как базовому указателю грамотно NEW устроить?

Автор:  Илья Ермаков [ Пятница, 02 Сентябрь, 2016 18:43 ]
Заголовок сообщения:  Re: NEW в процедуре.

Давайте код, на слух невозможно понять )

Автор:  prospero78 [ Пятница, 02 Сентябрь, 2016 18:52 ]
Заголовок сообщения:  Re: NEW в процедуре.

Код:
   TYPE
      tpGrad* = POINTER TO EXTENSIBLE RECORD (mTf.tpFaze)
      END;

PROCEDURE Init(VAR grad_:tpGrad; faze_:BYTE);
BEGIN
  NEW(grad_);
  mTf.Init(grad_.????) (* вот здесь как быть -- не догоняю *)
END Init;


Или здесь наследование не прокатывает?

Автор:  Иван Денисов [ Пятница, 02 Сентябрь, 2016 19:08 ]
Заголовок сообщения:  Re: NEW в процедуре.

prospero78 писал(а):
Хорошо. Вопрос в догонку. Я наследую через указатель -- указатель на расширяемую запись.
1. Так можно?
2. Как базовому указателю грамотно NEW устроить?


Вот старый примерчик. Вроде бы он был по книге:
Фримен Э. и др. Паттерны проектирования. Санкт-Петербург: Питер, 2011. 656 с.

Тут не только фабрика, но и еще "нечто" в стиле ББ.
Код:
MODULE MyTest;
   IMPORT  Log;
   
   TYPE
      Animal = POINTER TO ABSTRACT RECORD
         next: Animal
      END;
      Cat = POINTER TO RECORD (Animal) END;
      Dog = POINTER TO RECORD (Animal) END;
      Directory = POINTER TO RECORD
         root: Animal
      END;

   VAR
      dir: Directory;

   PROCEDURE (d: Directory) Add (a: Animal), NEW;
   VAR tmp: Animal;
   BEGIN
      IF d.root = NIL THEN
         d.root := a
      ELSE
         tmp := d.root;
         WHILE tmp.next # NIL DO tmp := tmp.next END;
         tmp.next := a
      END
   END Add;
   
   PROCEDURE (a: Animal) FeedMilk, NEW, ABSTRACT;
   
   PROCEDURE (a: Cat) FeedMilk;
   BEGIN
      Log.String("Mmm!"); Log.Ln;
   END FeedMilk;
   
   PROCEDURE (a: Dog) FeedMilk;
   BEGIN
      Log.String("No thanks!"); Log.Ln;
   END FeedMilk;
   
   (* Фабрика объетов *)
   PROCEDURE (d: Directory) New (type: INTEGER): Animal, NEW;
   VAR a: Animal; cat: Cat; dog: Dog;
   BEGIN
      CASE type OF 1:
         NEW(cat);
         a := cat;
      | 2 :
         NEW(dog);
         a := dog;
      ELSE END;
      dir.Add(a);
      
      RETURN a
   END New;
   
   PROCEDURE Test*;
      VAR a: Animal;
   BEGIN
      dir.root := NIL;
      (* add animals *)
      a := dir.New(1);
      a := dir.New(2);
      
      a := dir.root;
      WHILE a # NIL DO
         a.FeedMilk;
         a := a.next
      END
   END Test;

BEGIN
   NEW(dir);
   
END MyTest.

MyTest.Test


Вложения:
Test.odc [2.41 КБ]
Скачиваний: 666

Автор:  Илья Ермаков [ Пятница, 02 Сентябрь, 2016 20:48 ]
Заголовок сообщения:  Re: NEW в процедуре.

VAR-аргумент указательного типа должен в точности соответствовать типу формального параметра.

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 10:17 ]
Заголовок сообщения:  Re: NEW в процедуре.

У меня мысль пришла, что можно попробовать сделать через CASE type_ OF.
Но, это не очень элегантно, имхо. При добавлении нового типа, поверх базового типа придётся циферки придумывать.
В Компонентном Паскале есть прямая проверка типа, так что в процедуру (теоретически) достаточно передавать просто базовый класс.
И посетила меня ещё одна мысль: а незачем мне все типы определять как указатели. Ведь мне важен только верхний уровень. только он и должен быть указателем. При присвоении NIL всё остальное сборщик мусора подгребёт по полной программе))

Короче, спасибо всем за подсказки, буду пробовать)
Я правильно понимаю, что фактически, в своём примере я предлагаю реализацию фабрики классов?

Автор:  Илья Ермаков [ Суббота, 03 Сентябрь, 2016 12:28 ]
Заголовок сообщения:  Re: NEW в процедуре.

Вы фабрики используйте, фабрики!

Автор:  Иван Денисов [ Суббота, 03 Сентябрь, 2016 16:39 ]
Заголовок сообщения:  Re: NEW в процедуре.

prospero78 писал(а):
Я правильно понимаю, что фактически, в своём примере я предлагаю реализацию фабрики классов?

Нет, у тебя не фабрика. Фабрику смотри в моем примере Directory.

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 18:08 ]
Заголовок сообщения:  Re: NEW в процедуре.

Я понял отличие. Принимает что угодно, а на выходе объект.
Не, у меня задача попроще. Количество объектов известно заранее. И их нужно уничтожать по окончанию дорасчёта. А уничтожить можно только через NIL в указатели. Тогда модули будут выгружаться как положено.
Поэтому, мне указатель нужен только на самом верху. Вниз с ними работать смысла не имеет.

Или мне для выгрузки модулей, это не поможет?)))

Автор:  Иван Денисов [ Суббота, 03 Сентябрь, 2016 18:18 ]
Заголовок сообщения:  Re: NEW в процедуре.

prospero78 писал(а):
Я понял отличие. Принимает что угодно, а на выходе объект.
Не, у меня задача попроще. Количество объектов известно заранее. И их нужно уничтожать по окончанию дорасчёта. А уничтожить можно только через NIL в указатели. Тогда модули будут выгружаться как положено.
Поэтому, мне указатель нужен только на самом верху. Вниз с ними работать смысла не имеет.

Или мне для выгрузки модулей, это не поможет?)))

Никогда в ручную не приходилось присваивать куда-то NIL. КП сам видит, когда объекты больше не нужны. Если объект больше не используется, например, он удален из списка, то на него нигде нет ссылок и его сборщик сам удалит.

Задача главная это выгружать модули?

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 19:01 ]
Заголовок сообщения:  Re: NEW в процедуре.

Да, именно так, Вань. Но у меня модули не выгружаются сами. В том-то и фишка. Вот думаю, может, через указатели сейчас сделаю, что-то изменится)) Через NIL то уже явно ресурсы освобождаться будут)).
Ну и с точки зрения надёжности, мне не помешает указатели в добровольно-принудительном порядке в NIL приводить.
Вообще, у меня задумка есть вообще все объекты типа в конфиг собрать в одном месте)) Тогда все модули будут выгружаться, кроме этого конфига)

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

Автор:  Иван Денисов [ Суббота, 03 Сентябрь, 2016 19:25 ]
Заголовок сообщения:  Re: NEW в процедуре.

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

Это на самом деле не очень сложно, вот тут есть пара примеров
http://gitlab.molpit.org/bindings/sdl2

Модуль Sdl2StdWin во время "ручного" импорта в примерах Obx* устанавливает себя как реализацию абстрактного интерфейса.

Код:
      (* Load realisations for current platform *)
      IF Dialog.IsWindows() THEN
         ASSERT(Kernel.ThisMod('Sdl2StdWin') # NIL, 20)
      ELSIF Dialog.IsLinux() THEN
         ASSERT(Kernel.ThisMod('Sdl2StdLin') # NIL, 20)
      ELSE HALT(20) END;

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 19:42 ]
Заголовок сообщения:  Re: NEW в процедуре.

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

Автор:  Иван Денисов [ Суббота, 03 Сентябрь, 2016 19:55 ]
Заголовок сообщения:  Re: NEW в процедуре.

prospero78 писал(а):
Это понятно, что если один модуль импортирует другой, то, тот который уровнем глубже не может быть выгружен. Тут фишка получается, что какой-то модуль из верхнего уровня продолжает в памяти висеть, даже после закрытия окна. Так вот непонятно, почему такой модуль остаётся в памяти, если его ничего не держит, и соответственно, все остальные модули уровнями ниже?

А модули сами, как я понял, вообще не выгружаются... Я думал по началу, что было бы логично, если бы они сами выгружались, но не тут то было.

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 22:21 ]
Заголовок сообщения:  Re: NEW в процедуре.

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

Автор:  prospero78 [ Суббота, 03 Сентябрь, 2016 23:09 ]
Заголовок сообщения:  Re: NEW в процедуре.

Не побоялся залезть в Kernel, и оказалась задача с принудительной выгрузкой модулей вполне решаема!
Вот что я родил:
Код:
PROCEDURE Модуль_выгрузить(IN мод_: ARRAY OF CHAR);
   VAR
      модуль: мЯдро.Module;
   BEGIN
      модуль:=мЯдро.ThisMod(мод_);
      мЯдро.UnloadMod(модуль)
   END Модуль_выгрузить;

где, мЯдро := Kernel.

Не знаю, на сколько это безопасно, на зато проверено на 4-х модулях -- работает!!!)))

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/