Fortran中自定义类型的嵌套数据结构
Nested data structure of User-Defined Type in Fortran
我正在寻找一种在 Fortran 2008 中使用用户定义类型构建树结构的方法。虽然我可以使一些基本代码正常工作,但我遇到了无法查明的内存泄漏。
树结构不必过于通用,因为它被用作一次性插入和多次读取的存储类型,这就是我决定使用可分配表的原因。由于 Fortran 不允许将可分配类型用作其自身成员之一,因此我使用由指针引用的中间结构来存储可分配。因此,以下是我想使用但不允许使用的内容:
type :: invalid_section
type(invalid_section), dimension(:), allocatable :: subsections
end type
在下面的示例中,我使用了指向持有可分配类型的指针的惰性分配(仅当有子节点指向 add/present 时才分配它)。
module sectiontest
type :: section
type(subsections), pointer :: subsections_ => null()
contains
procedure, pass(self) :: section_assign
generic :: assignment(=) => section_assign
final :: section_cleanup, section_cleanup_arr
end type
type :: subsections
type(section), dimension(:), allocatable :: arr
end type
interface section
module procedure constructor
end interface
contains
type(section) function constructor(subsections)
type(section), optional, intent(in) :: subsections(:)
integer :: idx
print *, "constructor"
if (present(subsections)) then
print *, "allocating subsection"
allocate(constructor%subsections_)
allocate(constructor%subsections_%arr(size(subsections)))
do idx=1,size(subsections)
! make sure we recursively copy everything
constructor%subsections_%arr(idx) = subsections(idx)
enddo
endif
end function
recursive subroutine section_assign(self, rhs)
class(section), intent(inout) :: self
type(section), intent(in) :: rhs
integer :: idx
print *, "assign"
if (associated(self%subsections_)) then
deallocate(self%subsections_)
endif
if (associated(rhs%subsections_)) then
print *, "allocation subsection"
allocate(self%subsections_)
allocate(self%subsections_%arr(size(rhs%subsections_%arr)))
do idx=1,size(rhs%subsections_%arr)
self%subsections_%arr(idx) = rhs%subsections_%arr(idx)
enddo
endif
end subroutine
recursive subroutine section_cleanup(sec)
type(section), intent(inout) :: sec
print *, "section_cleanup"
if (associated(sec%subsections_)) then
print *, " deallocated a subsection"
deallocate(sec%subsections_)
endif
end subroutine
recursive subroutine section_cleanup_arr(arr)
type(section), dimension(:), intent(inout) :: arr
integer :: idx
print *, "deallocating array of sections of size:", size(arr)
do idx=1,size(arr)
print *, "deallocating subsection array index", idx
if (associated(arr(idx)%subsections_)) then
print *, " deallocated a subsection"
deallocate(arr(idx)%subsections_)
endif
end do
end subroutine
subroutine demo()
type(section) :: root
root = section(subsections=[ &
section(subsections=[section(), section(), section()]), &
section() &
])
end subroutine
end module sectiontest
program main
use sectiontest
implicit none
call demo()
end program
从 gfortran
(7 和 9)、flang
和 nagfor
我得到来自 constructor
中的 allocate(constructor%subsections_)
的直接内存泄漏。
来自 gfortran-7
并使用 -fsanitize=address
构建:
==26536==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 48 byte(s) in 1 object(s) allocated from:
#0 0x7f965539c510 in malloc (/usr/lib64/libasan.so.4+0xdc510)
#1 0x407e35 in __sectiontest_MOD_constructor /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe.f90:31
#2 0x40432a in __sectiontest_MOD_demo /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe.f90:92
#3 0x4090d9 in MAIN__ /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe_prog.f90:5
#4 0x409119 in main /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe_prog.f90:2
#5 0x7f96543c2f89 in __libc_start_main (/lib64/libc.so.6+0x20f89)
我正在寻找替代实现(但最好是类似的优雅初始化)或内存泄漏的解释和可能的解决方案。
Fortran 2008 支持包含所定义类型的可分配组件的类型。这将代码简化为:
module sectiontest
type :: section
type(section), allocatable :: subsections(:)
end type
contains
subroutine demo()
type(section) :: root
root = section( subsections=[ &
section(subsections=[section(), section(), section()]), &
section() ])
end subroutine
end module sectiontest
program main
use sectiontest
implicit none
call demo()
end program
最新版本的 gfortran 支持此语言功能。
对于不能充分支持 Fortran 2008 的编译器,问题中的代码是一种合理的解决方法,并且可以在正确实现 Fortran 2003 的编译器上运行。
但是,gfortran(至少达到 9.1.1)没有正确实现函数结果的最终确定 - 因此观察到内存泄漏。
我正在寻找一种在 Fortran 2008 中使用用户定义类型构建树结构的方法。虽然我可以使一些基本代码正常工作,但我遇到了无法查明的内存泄漏。
树结构不必过于通用,因为它被用作一次性插入和多次读取的存储类型,这就是我决定使用可分配表的原因。由于 Fortran 不允许将可分配类型用作其自身成员之一,因此我使用由指针引用的中间结构来存储可分配。因此,以下是我想使用但不允许使用的内容:
type :: invalid_section
type(invalid_section), dimension(:), allocatable :: subsections
end type
在下面的示例中,我使用了指向持有可分配类型的指针的惰性分配(仅当有子节点指向 add/present 时才分配它)。
module sectiontest
type :: section
type(subsections), pointer :: subsections_ => null()
contains
procedure, pass(self) :: section_assign
generic :: assignment(=) => section_assign
final :: section_cleanup, section_cleanup_arr
end type
type :: subsections
type(section), dimension(:), allocatable :: arr
end type
interface section
module procedure constructor
end interface
contains
type(section) function constructor(subsections)
type(section), optional, intent(in) :: subsections(:)
integer :: idx
print *, "constructor"
if (present(subsections)) then
print *, "allocating subsection"
allocate(constructor%subsections_)
allocate(constructor%subsections_%arr(size(subsections)))
do idx=1,size(subsections)
! make sure we recursively copy everything
constructor%subsections_%arr(idx) = subsections(idx)
enddo
endif
end function
recursive subroutine section_assign(self, rhs)
class(section), intent(inout) :: self
type(section), intent(in) :: rhs
integer :: idx
print *, "assign"
if (associated(self%subsections_)) then
deallocate(self%subsections_)
endif
if (associated(rhs%subsections_)) then
print *, "allocation subsection"
allocate(self%subsections_)
allocate(self%subsections_%arr(size(rhs%subsections_%arr)))
do idx=1,size(rhs%subsections_%arr)
self%subsections_%arr(idx) = rhs%subsections_%arr(idx)
enddo
endif
end subroutine
recursive subroutine section_cleanup(sec)
type(section), intent(inout) :: sec
print *, "section_cleanup"
if (associated(sec%subsections_)) then
print *, " deallocated a subsection"
deallocate(sec%subsections_)
endif
end subroutine
recursive subroutine section_cleanup_arr(arr)
type(section), dimension(:), intent(inout) :: arr
integer :: idx
print *, "deallocating array of sections of size:", size(arr)
do idx=1,size(arr)
print *, "deallocating subsection array index", idx
if (associated(arr(idx)%subsections_)) then
print *, " deallocated a subsection"
deallocate(arr(idx)%subsections_)
endif
end do
end subroutine
subroutine demo()
type(section) :: root
root = section(subsections=[ &
section(subsections=[section(), section(), section()]), &
section() &
])
end subroutine
end module sectiontest
program main
use sectiontest
implicit none
call demo()
end program
从 gfortran
(7 和 9)、flang
和 nagfor
我得到来自 constructor
中的 allocate(constructor%subsections_)
的直接内存泄漏。
来自 gfortran-7
并使用 -fsanitize=address
构建:
==26536==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 48 byte(s) in 1 object(s) allocated from:
#0 0x7f965539c510 in malloc (/usr/lib64/libasan.so.4+0xdc510)
#1 0x407e35 in __sectiontest_MOD_constructor /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe.f90:31
#2 0x40432a in __sectiontest_MOD_demo /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe.f90:92
#3 0x4090d9 in MAIN__ /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe_prog.f90:5
#4 0x409119 in main /users/tiziano/work/tests/fortran/cp2k_input_parser/recursive_mwe_prog.f90:2
#5 0x7f96543c2f89 in __libc_start_main (/lib64/libc.so.6+0x20f89)
我正在寻找替代实现(但最好是类似的优雅初始化)或内存泄漏的解释和可能的解决方案。
Fortran 2008 支持包含所定义类型的可分配组件的类型。这将代码简化为:
module sectiontest
type :: section
type(section), allocatable :: subsections(:)
end type
contains
subroutine demo()
type(section) :: root
root = section( subsections=[ &
section(subsections=[section(), section(), section()]), &
section() ])
end subroutine
end module sectiontest
program main
use sectiontest
implicit none
call demo()
end program
最新版本的 gfortran 支持此语言功能。
对于不能充分支持 Fortran 2008 的编译器,问题中的代码是一种合理的解决方法,并且可以在正确实现 Fortran 2003 的编译器上运行。
但是,gfortran(至少达到 9.1.1)没有正确实现函数结果的最终确定 - 因此观察到内存泄漏。