Как я могу выполнить unchecked_deallocation абстрактных классов в Ada?

#abstract-class #dynamic-memory-allocation #ada

#абстрактный класс #динамическое выделение памяти #ada

Вопрос:

Я довольно хорошо знаю Ada, но я все еще борюсь с OO в целом и, в частности, в Ada. Таким образом, вполне может быть, что я просто упускаю какой-то момент.

Рассмотрим структуру данных, подобную дереву. Объекты, хранящиеся в дереве, имеют абстрактный тип. Я хочу получить полный контроль над освобождением (с помощью Ada.Finalization), потому что я реализую структуру данных с безопасными указателями. Это означает, что при освобождении дерева поддеревья не должны освобождаться, если на него все еще есть ссылка.

В этом сценарии требуется освободить конкретные объекты, на которые ссылаются в структуре данных. Мне кажется, что для этого требуется абстрактное unchecked_deallocation . Есть ли простой способ сделать это? Я также рассмотрел возможность объявления абстрактной свободной подпрограммы, которая должна быть реализована экземплярами абстрактного типа. Безуспешно.

Я еще не проверил стандартные библиотеки на предмет подходящей структуры данных. В настоящее время мне просто интересно узнать о самой проблеме.

Комментарии:

1. За десятилетия чтения новостной группы comp.lang.ada я заметил, что функции Ada, которые чаще всего приводят к проблемам, — это анонимный доступ к типам объектов и программирование с помощью расширения типа. Я пришел к выводу, что язык был бы лучше без этих функций и избегал их использования. Любое сравнение одного и того же дизайна, реализованного с расширением типа и без него, показывает, что версия с расширением типа короче, но сложнее для понимания. Расширение типа всегда нарушает S / W-инженерный принцип локальности. Таким образом, компетентный инженер S / W не использует расширение типа.

2. В некоторых областях, таких как потоки или пользовательские интерфейсы, вы никуда не пойдете без расширения типа. На самом деле, если вы хотите избежать каких-либо проблем в программировании, вам лучше вообще избегать программирования. Тогда вы в безопасности…

Ответ №1:

Это было забавно дождливым воскресным утром!

Основной трюк заключается в использовании Foo’Class для освобождаемого типа и access Foo’Class для типа доступа.

 generic
   type T is abstract tagged private;
   type T_Access is access T'CLass;
package Abstract_Deallocation is
   type Holder is private;

   function Is_Empty (H : Holder) return Boolean;

   procedure Add (To : in out Holder; Item : T_Access);

   procedure Release (H : in out Holder)
   with Post => Is_Empty (H);
private
   type Holder is new T_Access;

   function Is_Empty (H : Holder) return Boolean
   is (H = null);
end Abstract_Deallocation;
  
 with Ada.Unchecked_Deallocation;
package body Abstract_Deallocation is
   procedure Free is new Ada.Unchecked_Deallocation
     (T'Class, T_Access);

   procedure Add (To : in out Holder; Item : T_Access) is
   begin
      To := Holder (Item);
   end Add;

   procedure Release (H : in out Holder) is
   begin
      Free (T_Access (H));
   end Release;
end Abstract_Deallocation;
  
 with Abstract_Deallocation;
procedure Abstract_Deallocation_Test is
   type Actual_T is abstract tagged null record;
   type Actual_T_Access is access all Actual_T'Class;

   package Demo is new Abstract_Deallocation
     (T        => Actual_T,
      T_Access => Actual_T_Access);

   type Concrete_T is new Actual_T with null record;
   Holder : Demo.Holder;
begin
   Demo.Add (Holder, new Concrete_T);
   Demo.Release (Holder);
end Abstract_Deallocation_Test;
  

Комментарии:

1. Оглядываясь назад, я думаю, что для Add я бы использовал либо предварительное условие, чтобы Holder быть пустым, либо Release любое существующее содержимое.