Типы доступа для выделенного массива в Ada - PullRequest
3 голосов
/ 07 января 2020

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

Чтобы сохранить размер стека, я начал использовать типы доступа, но я не хочу делать динамическое распределение c.

У меня есть что-то вроде этого:

type My_Array_Type is array (Natural range<>) of Integer;
type My_Array_Type_Ptr is access all My_Array_Type;

procedure Do_Stuff(Things : My_Array_Type_Ptr) is
begin
 -- things 
end Do_Stuff;

procedure Do_Stuff(Num_Things : Integer) is
  Things : My_Array_Type_Ptr := new My_Array_Type(1..Num_Things);
begin
  Do_Stuff(Things);
  -- more things
end Do_Stuff;

ОДНАКО, я бы хотел сделать что-то вроде этого:

type My_Array_Type is array (Natural range<>) of Integer;

procedure Do_Stuff(Things : access all My_Array_Type) is
begin
 -- things 
end Do_Stuff;

procedure Do_Stuff(Num_Things : Integer) is
  Things : aliased My_Array_Type(1..Num_Things);
begin
  Do_Stuff(Things'Access);
  -- more things
end Do_Stuff;

Но, очевидно, это не так не работает

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

Кроме того, в качестве примечания: я постоянно вижу противоречивую информацию о том, динамически ли распределяется что-то, нужно ли это выпускать или нет - я читал, что большинство реализаций не имеют сборщиков мусора но они не нужны. Кто-нибудь может уточнить - в примере, который я показал первым, мне нужно явно освободить?

РЕДАКТИРОВАТЬ: После попытки решения, упомянутых ниже, я остановился на комбинации двух вещей:

  1. Используя механизм передачи параметров in out.
  2. Снижение требований к хранилищу моего типа данных.

Поэтому вместо Integer я использую:

type UInt8 is new Interfaces.Unsigned_8;

Что:

type UInt8 is mod 2**8
     with Size => 8;

Это прекрасно работает, так как мои значения не ' На самом деле это целые числа, они на самом деле являются беззнаковыми байтами.

Ответы [ 2 ]

6 голосов
/ 07 января 2020

В Ada вам действительно не нужно использовать типы доступа для этой ситуации.

Замечания ниже для нативного кода Ada; для импортированных (и я предполагаю экспортированных) подпрограмм сгенерированный код, очевидно, должен подчиняться соглашениям на иностранных языках.

Режим параметра (разрешено ли вам писать в него, разрешено ли (если разрешено) для записи в него) оно имеет некоторое начальное значение) отличается от механизма передачи параметров.

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

Ада будет выглядеть следующим образом:

with Ada.Text_IO; use Ada.Text_IO;
with System.Storage_Elements;
procedure Jsinglet is

   type My_Array_Type is array (Natural range<>) of Integer;

   procedure Do_Stuff_1 (Things : in out My_Array_Type) is
   begin
      Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
   end Do_Stuff_1;

   procedure Do_Stuff (Num_Things : Integer) is
      Things : My_Array_Type (1 .. Num_Things);
   begin
      Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
      Do_Stuff_1 (Things);
   end Do_Stuff;

begin
   Do_Stuff (42);
end Jsinglet;

Запуск программы приводит к

$ ./jsinglet 
 140732831549024
 140732831549024

показывает, что адрес был передан, а не значение.

Режим in out для параметра Do_Stuff_1 означает, что Do_Stuff_1 может прочитать содержимое переданного ему массива перед записью в it.

out будет означать, что Do_Stuff_1 не должен читать содержимое до тех пор, пока сам его не напишет (он может , но - в зависимости от параметра тип - может считывать неинициализированные или инициализированные по умолчанию данные)

in будет означать, что содержимое не может быть записано.

4 голосов
/ 07 января 2020

Начиная с Ada2012 вы можете пометить параметры как с псевдонимом , и они будут переданы по ссылке, но ваш исходный объект также должен быть помечен или иметь псевдоним.

РЕДАКТИРОВАТЬ: это не может быть Массив либо появляется, так что смотрите ниже. Параметры с псевдонимами работают для таких типов, как целые числа, перечисления, записи и т. Д. c. хотя.

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

type My_Array_Type is array (Natural range<>) of Integer;
type By_Reference(Length : Natural) is tagged record  -- or limited
   Elements : My_Array_Type(1..Length);
end record;

procedure Do_Stuff(Things : in out By_Reference) is
begin
 -- things 
end Do_Stuff;

procedure Do_Stuff(Num_Things : Integer) is
  Things : By_Reference(Num_Things);
begin
  Do_Stuff(Things);
  -- more things
end Do_Stuff;

Для вашего вопроса освобождения ваш пример должен явно освободить память. Есть способы получить автоматическое c освобождение от обязательств:

  • Компилятор с сборкой мусора (я не знаю ни одного)
  • Пользовательская сторонняя библиотека, которая предоставляет ее
  • Использование держатель или контейнер из Ada.Containers
  • Используйте локальный (не на уровне библиотеки) именованный тип доступа с указанным размером хранилища (ваш тип доступа - уровень библиотеки и не указан размер хранилища). Когда тип доступа выходит из области видимости, он освобождается.
...