Переменные удаляются в массивах Fortran?
У меня есть следующий код с абстрактным типом, унаследованным типом и короткой программой, где я создаю объект и сохраняю его в массиве.
module m
implicit none
type :: container
class(a), allocatable :: item
end type container
type, abstract :: a
integer, public :: num
end type a
type, extends(a) :: b
integer, public :: num2
end type b
end module m
program mwe
use m
implicit none
class(a), allocatable :: o1
class(container), allocatable :: arr(:)
o1 = b(1, 2)
allocate(arr(2))
arr(1) = container(o1)
select type(t => o1)
type is(b)
write(*,*) t%num, t%num2
end select
select type(t => arr(1)%item)
type is(b)
write(*,*) t%num, t%num2
end select
end program mwe
Проблема в том, что вывод выглядит так:
1 2
1 0
Как видно, та же самая переменная, хранящаяся в массиве, имеет вторую переменную, аннулированную. Почему это происходит? Это потому, что массив имеет тип a
, который содержит только первую переменную?
Я компилирую код с ifort version 18.0.3
,
2 ответа
Как и в случае с ответом Риперо, можно сказать, что любой вывод из программы действителен. Тем не менее, мы можем сделать простую модификацию кода, чтобы сделать его правильным Fortran. 1 Этот ответ касается этой модифицированной версии.
Я бы назвал этот неожиданный вывод и обратился за помощью к поставщику компилятора.
Использование конструктора структуры с полиморфными размещаемыми компонентами - одна из новых областей в Фортране. Компиляторам может потребоваться некоторое время, чтобы наверстать упущенное или сделать это правильно.
Я проверил ваш код с Intel Fortran 18.0.2 и вижу тот же результат.
На ваш вопрос
Это потому, что массив имеет тип
a
, который содержит только первую переменную?
Нет: в select type
расстаться с выходом t
является неполиморфным объектом типа b
,
Вы можете обойти эту проблему, избегая использования конструктора структуры:
arr(1)%item = o1
Я также вижу, что компиляторы Intel до 18.0.2 делают что-то другое.
1 с декларацией
class(container), allocatable :: arr(:)
arr
является полиморфным и выделяемым. Как отмечает Риперо, это означает, что arr(1)
, элемент arr
полиморфный. Тем не менее, как элемент массива, arr(1)
сам по себе не является полиморфным и поэтому не может быть слева от внутреннего оператора присваивания. Мы можем изменить код двумя способами: предоставить определенное назначение или сделать arr
не полиморфный. В коде вопроса, по-видимому, нет причин для того, чтобы контейнер был полиморфным, поэтому я рассмотрю
type(container), allocatable :: arr(:)
Кроме того, как обсуждалось в комментариях к вопросу, если вы хотите работать с gfortran 8 или более ранней версией, чтобы увидеть, что происходит, вам также следует изменить код в вопросе, чтобы определение производного типа container
приходит после определения производного типа a
,
Я верю
arr(1) = container(o1)
является недействительным Fortran 2008. Это внутреннее утверждение присваивания, но в разделе 7.2.1.2 стандарта говорится, что
В собственном операторе присваивания: (1) если переменная полиморфна, она должна быть размещаемой, а не произвольной.
Насколько я вижу, arr(1)
является полиморфным, но не выделяемым, поэтому совместимый со стандартами компилятор должен выдать ошибку и прервать компиляцию.
Если мои рассуждения верны, тот факт, что компилятор Intel Fortran компилирует этот код, является ошибкой компилятора и должен быть сообщен в Intel.