Продление жизни переменной

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

Проблема

У меня есть функция:

function Make_Option (Title : String) return Access_Option is
    O : aliased Option := (
            Title_Len => Title'Length, 
            Title => Title);
begin -- Make_Option
    return O'Unrestricted_Access;
end Make_Option;

Предполагается, что эта функция создает новый пункт меню для пользователя, который, в свою очередь, может быть вставлен в меню (которое вы можете увидеть в среде на основе терминала). Вы все, вероятно, вздыхаете, поскольку совершенно очевидно, что переменная O будет освобождена в конце этой функции (насколько я понимаю). Таким образом, использование Unrestricted_Access здесь просто глупо, но оно отражает результат того, что я пытаюсь выполнить (поскольку этот код действительно успешно компилируется).

Access_Option определяется следующим образом:

type Access_Option is access all Option;

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

Вне всякого сомнения, было бы неплохо, если бы мы могли вместо этого использовать для этого атрибут Access, поскольку тогда компилятор удостоверился бы, что время жизни переменной O, на которую мы ссылаемся, достаточно велико, но поскольку время жизни на самом деле существует только до конец функции Make_Option, мы получаем следующее:

non-local pointer cannot point to local object

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

Мыслительный процесс

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

Возможно, у вас есть какая-то очередь объектов для обработки этого? Ада вообще автоматически освобождает ресурсы? Гах. Я сбит с толку.

Действительно ли возможно каким-то образом поместить переменную O за пределы области действия для освобождения, чтобы затем вручную освободить ее позже?


person D. Ataro    schedule 27.12.2017    source источник
comment
См. также Эффект объявления типа доступа при освобождении.   -  person trashgod    schedule 27.12.2017


Ответы (3)


Учитывая приведенный выше пример, гораздо более простой подход — просто создать массив Unbounded_String:

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_Io;

procedure Str_Arrays is
   type Arr is array(1..10) of Unbounded_String;
   A : Arr;
begin
   for S of A loop
      S := To_Unbounded_String("Hello World!");
   end loop;
   for S of A loop
      Put_Line(To_String(S));
   end loop;
end Str_arrays;
person Jim Rogers    schedule 27.12.2017

Не пытайтесь это сделать.

Есть два альтернативных варианта:

1) Используйте Ada.Containers.Indefinite_Vectors вместо простого массива.

2) Дайте дискриминанту записи значение по умолчанию. Затем вы можете сохранить его в обычном массиве.

person Jacob Sparre Andersen    schedule 27.12.2017
comment
Вы можете найти Ada.Containers.{Indefinite_,}{Hashed,Ordered}_Maps полезным, если параметры могут быть идентифицированы, например. перечисления или даже строки. - person Simon Wright; 28.12.2017

Кажется, вы заново изобретаете ограниченную строку. Альтернативы включают

  • Использование экземпляра Ada.Strings.Bounded.Generic_Bounded_Length
  • Использование Ada.Strings.Unbounded
  • Использование неопределенного контейнера (Ada.Containers.Indefinite_*) для хранения типа String
person Jeffrey R. Carter    schedule 31.12.2017