dan*_*opa 1 arrays polymorphism fortran allocation gfortran
目标是创建一个单一的分配例程,它可以处理任何类型的一级分配。然后,我们的代码库可以使用标准化的错误捕获进行一次调用。
编译器错误如下:
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
Run Code Online (Sandbox Code Playgroud)
这段代码可以修改吗?
测试代码尝试分配一个整数数组,然后分配一个实数数组:
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
Run Code Online (Sandbox Code Playgroud)
代码的第一个版本依赖于一个select type结构,如FORTRAN: polymorphism allocation 中所示。使用的另一个参考是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)
Run Code Online (Sandbox Code Playgroud)
您在语言中遇到了故意限制,该限制是为了防止过程将对象分配给与实际参数的声明类型不匹配的某种类型。考虑如果您的分配器将对应于 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
Run Code Online (Sandbox Code Playgroud)
您可以将所有这些特定程序放在一个通用名称后面。
但是,在开始之前,请注意,在现代 Fortran 中,即使没有 ALLOCATE 语句也可以分配可分配的东西 - 对可分配变量的简单赋值可能会导致它被分配。对于这些情况,您无法处理错误消息。还有大量的编码结构会导致编译器为自己的内部需求“分配”内存,这又是一次,您无法处理错误。在较低级别,操作系统实际满足程序对内存的请求的方式也对您不利 - 系统可能被过度使用,并且操作系统可能不会在分配之后很久才向进程报告内存不足错误声明已完成。结合,在可用内存非常低并且尝试分配小对象失败的情况下,可能没有足够的可用内存供编译器甚至执行您的错误报告代码。还有一个问题是编译器的运行时可以更好地了解失败的原因和程序的状态,它可以通过简单的整数代码和字符消息进行通信 - 例如,编译器的运行时可以为用户提供堆栈跟踪或类似的,除了它可以以其他方式传递回程序的任何消息之外。
总之,对于小分配,程序员提供的错误报告可能不是很有效率。
对于较大的分配可能非常值得,其中特定失败的概率较高并且很可能成功传达原因并采取行动(“您的问题维度太大!请缩小并重试.. .") 的用户。