首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fortran中用户定义类型的嵌套数据结构

Fortran中用户定义类型的嵌套数据结构
EN

Stack Overflow用户
提问于 2019-07-11 15:29:10
回答 1查看 622关注 0票数 0

我正在寻找一种方法来构建一个树结构使用用户定义的类型在Fortran 2008。虽然我可以让一些基本的代码工作,但我遇到了内存泄漏,我无法精确定位。

树结构不必过于通用,因为它被用作一次性插入和多读类型的存储,这就是为什么我决定使用可分配的。由于Fortran不允许使用可分配的类型作为自己的成员之一,所以我使用指针引用的中间结构来存储可分配的类型。因此,以下是我想使用但不允许使用的内容:

代码语言:javascript
复制
type :: invalid_section
  type(invalid_section), dimension(:), allocatable :: subsections
end type

在下面的示例中,我使用指向可分配类型的指针的延迟分配(只有当有子节点要添加/呈现时才分配它)。

代码语言:javascript
复制
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
代码语言:javascript
复制
program main
   use sectiontest
   implicit none

   call demo()
end program

gfortran (7和9)、flangnagfor,我从constructor中的allocate(constructor%subsections_)获得直接的内存泄漏。

这里来自gfortran-7,由-fsanitize=address建造

代码语言:javascript
复制
==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)

我正在寻找另一种实现(但最好是类似的优雅初始化),或者是对内存泄漏的解释和可能的解决方案。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-12 23:48:16

Fortran 2008支持包含所定义类型的可分配组件的类型。这将代码简化为:

代码语言:javascript
复制
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 )没有正确地实现函数结果的最后确定--因此出现了内存泄漏。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56992681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档