Элемент-указатель производного типа от Fortran не копируется - PullRequest
0 голосов
/ 13 июня 2018

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

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

MWE:

program mwe
  implicit none

  type a
    integer var
  end type a

  type b
    type(a), pointer :: elt
  end type b

  interface b
    procedure construct_b
  end interface

  type(b) val_func, val_sub

  val_func = get_new_b(52)
  write(*,*) 'using function: ', val_func%elt%var

  call new_b(val_sub, 55)
  write(*,*) 'using subroutine: ', val_sub%elt%var

contains

  function construct_b(elt) result(r)
    class(a), target, intent(in) :: elt
    type(b) r

    r%elt => elt
  end function

  function get_new_b(n) result(r)
    integer, intent(in) :: n
    type(b) r

    type(a) elt

    elt = a(n)
    r = b(elt)
    write(*,*) 'get_new_b:      ', r%elt%var
  end function

  subroutine new_b(r, n)
    type(b), intent(inout) :: r
    integer, intent(in) :: n

    type(a) elt

    elt = a(n)
    r = b(elt)
    write(*,*) 'new_b:            ', r%elt%var
  end subroutine

end program mwe

Использование gfortran 5.4.0,

$ gfortran -o mwe.x mwe.f90
$ ./mwe.x
 get_new_b:                52
 using function:    127919104
 new_b:                      55
 using subroutine:    127919104

Ожидаемый результат:

 get_new_b:                52
 using function:           52
 new_b:                      55
 using subroutine:           55

1 Ответ

0 голосов
/ 13 июня 2018

Внутри get_new_b процедуры вы выполняете:

type(a) elt    
elt = a(n)
r = b(elt)

Это означает, что вы создаете локальную переменную elt внутри функции, затем вы вызываете constructor_b (через b интерфейс) с этой переменной.Внутри constructor_b происходит следующее:

type(b) r
r%elt => elt

Т.е. вы создаете новую переменную type(b) и делаете указатель на связь между ее полем elt и переменной elt, которую вы передали.

Проблема в том, что фактический аргумент elt, который вы передали в качестве параметра, local в область действия функции get_new_b.Когда элемент управления возвращается к основной программе, цель указателя (эта переменная elt, которую вы создали внутри функции) перестает существовать, указатель затем «болтается».

У вас никогда не должно быть указателяк переменной, которая выходит за рамки.

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

Но если указатель - то, что вам нужно, убедитесь, что его цель никогда не станет неопределенной до переменной с компонентом указателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...