Процедура выделения полиморфного массива в Fortran

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

Ошибка компилятора следующая:

generic_allocation.f08:32:27:

         call myAllocator ( array_int, source_int, lambda )
                           1
Error: Actual argument to ‘myarray’ at (1) must be polymorphic
generic_allocation.f08:33:27:

         call myAllocator ( array_real, source_real, lambda )
                           1
Error: Actual argument to ‘myarray’ at (1) must be polymorphic

Можно ли исправить этот код?

Тестовый код пытается выделить целочисленный массив, а затем реальный массив:

module mAllocator
    implicit none
contains
    subroutine myAllocator ( myArray, source_type, lambda )
        class ( * ), allocatable, intent ( inout ) :: myArray ( : )
        class ( * ),              intent ( in )    :: source_type
        integer,                  intent ( in )    :: lambda

        integer                 :: alloc_status  = 0
        character ( len = 512 ) :: alloc_message = ''
            allocate ( myArray ( 1 : lambda ), source = source_type, stat = alloc_status, errmsg = alloc_message )
            if ( alloc_status /= 0 ) then
                write ( *, "( ' allocation  errmsg = ', g0, '.' )" ) trim ( alloc_message )
                stop 'Fatal error in subroutine myAllocator'
            end if
    end subroutine myAllocator
end module mAllocator

program generic_allocation

    use mAllocator, only : myAllocator

    implicit none

    integer, parameter   :: lambda = 10
    integer, parameter   :: source_int = 1
    real,    parameter   :: source_real = 1.0

    integer, allocatable :: array_int  ( : )
    real,    allocatable :: array_real ( : )
        call myAllocator ( array_int, source_int, lambda )
        call myAllocator ( array_real, source_real, lambda )
end program generic_allocation

Первая версия кода основывалась на конструкции select type, как показано в FORTRAN: выделение полиморфизма. Еще одна используемая ссылка — полиморфизм, функции и распределение Fortran.

Версия gfortran 6.0.

$ gfortran -v
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/opt/gnu/6.0/libexec/gcc/x86_64-pc-linux-gnu/6.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ./configure --prefix=/opt/gnu/6.0 --enable-languages=c,c++,fortran,lto --disable-multilib --disable-werror
Thread model: posix
gcc version 6.0.0 20160227 (experimental) (GCC) 

person dantopa    schedule 09.05.2016    source источник
comment
Цель состоит в том, чтобы создать единую процедуру распределения, которая может обрабатывать любой тип распределения первого ранга. Разве это не то, что обеспечивает allocate?   -  person High Performance Mark    schedule 10.05.2016


Ответы (1)


Вы столкнулись с преднамеренным ограничением языка, введенным для предотвращения присвоения процедуре объекта какого-либо типа, который не соответствует объявленному типу фактического аргумента. Подумайте, что произойдет, если ваш распределитель присвоит фиктивному аргументу, соответствующему array_int, тип REAL.

Вы не можете достичь своей цели с помощью одной процедуры, однако вам может сойти с рук написание одного фрагмента исходного кода, который вы затем ВКЛЮЧАЕТЕ в тело нескольких процедур, по одной для каждого объявленного типа (и типа), который вы хотите иметь дело с.

! In AllocateBody.i90
integer, intent(in) :: lambda
integer                 :: alloc_status
character ( len = 512 ) :: alloc_message
allocate ( myArray ( 1 : lambda ),  &
    source = source_type,  &
    stat = alloc_status,  &
    errmsg = alloc_message )
if ( alloc_status /= 0 ) then
  write ( *, "( ' allocation  errmsg = ', g0, '.' )" )  &
      trim ( alloc_message )
  stop 'Fatal error in subroutine myAllocator'
end if    


! Elsewhere.
subroutine my_allocator_integer(myArray, source_type, lambda )
  integer, intent(out), allocatable :: myArray(:)
  integer, intent(in) :: source_type
  include 'AllocateBody.i90'
end subroutine my_allocator_integer

subroutine my_allocator_real(myArray, source_type, lambda )
  real, intent(out), allocatable :: myArray(:)
  real, intent(in) :: source_type
  include 'AllocateBody.i90'
end subroutine my_allocator_real

subroutine my_allocator_foo(myArray, source_type, lambda )
  type(foo), intent(out), allocatable :: myArray(:)
  type(foo), intent(in) :: source_type
  include 'AllocateBody.i90'
end subroutine my_allocator_foo

Вы можете поместить все эти конкретные процедуры под одним общим именем.

Однако, прежде чем вы приступите к этому, обратите внимание, что в современном Фортране выделяемые объекты могут быть выделены даже без оператора ALLOCATE — простое присвоение выделяемой переменной может привести к тому, что она будет ALLOCATED. У вас нет возможности обрабатывать сообщения об ошибках для таких случаев. Существует также очень большое количество конструкций кодирования, которые приводят к тому, что компилятор «выделяет» память для своих внутренних нужд, для которых, опять же, у вас нет возможности обрабатывать ошибки. На более низком уровне способ, которым операционные системы фактически выполняют запросы программы на память, также работает против вас — система может быть перегружена, и операционная система может не сообщать процессу об ошибке нехватки памяти до тех пор, пока не будет выделена память. заявление было завершено. В сочетании, в ситуации, когда доступной памяти очень мало и попытка выделить небольшой объект не удалась, возможно, компилятору не хватает памяти даже для выполнения вашего кода сообщения об ошибке. Существует также проблема, заключающаяся в том, что среда выполнения компилятора имеет лучшее представление о причинах сбоя и состоянии программы, которое она может передать с помощью простого целочисленного кода и символьного сообщения — например, среда выполнения компилятора может предоставить пользователю трассировку стека. или подобное, в дополнение к любому сообщению, которое в противном случае могло бы быть передано обратно в программу.

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

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

person IanH    schedule 10.05.2016