#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
любое существующее содержимое.