Fortran如何释放链表(linked lists)的内存?

7

我希望能在Fortran中使用链表来保存未定义长度的数据。

我的设置如下:

TYPE linked_list
    INTEGER :: data
    TYPE(linked_list) :: next_item => NULL()
END TYPE

现在假设我创建了这样一个列表:
TYPE(LINKED_LIST) :: example_list
example_list%data =1
ALLOCATE(example_list%next_item)
example_list%next_item%data = 2
ALLOCATE(example_list%next_item%next_item)
example_list%next_item%next_item%data = 3

我的问题是,如果我执行以下操作:
DEALLOCATE(example_list)

所有嵌套级别的元素是否也会被释放,还是我需要遍历列表到最深处并从最深处向上进行释放?


4
我很久以前用Fortran做过这个,但我非常确定你必须手动取消分配内存。如果你只是取消分配头部,那么你会失去引用并造成内存泄漏。 - ChrisF
是的,我非常害怕那个。不过我必须说,我遇到了麻烦,什么来着,自己实现垃圾回收? - EMiller
你无法实现内存管理的Fortran。 - Stefano Borini
这是讽刺话还是一个事实陈述? - EMiller
1
@emiller 请确保你的所有数组都是可分配的。每个 allocate 语句都需要与一条 deallocate 语句匹配。只在必要或非常方便的情况下使用指针。如果你遵循这三点,就不会出问题了。Fortran 强制你跟踪内存,这是我非常欣赏 Fortran 的地方 - 它阻止了懒惰编程,让你更好地了解自己的程序。很棒的问题和答案。 - milancurcic
显示剩余4条评论
1个回答

10

你需要手动释放每个节点。这就是“面向对象”风格派上用场的地方。

module LinkedListModule
    implicit none
    private

    public :: LinkedListType
    public :: New, Delete
    public :: Append

    interface New
        module procedure NewImpl
    end interface

    interface Delete
        module procedure DeleteImpl
    end interface

    interface Append
        module procedure AppendImpl
    end interface

    type LinkedListType
        type(LinkedListEntryType), pointer :: first => null()
    end type

    type LinkedListEntryType
        integer :: data
        type(LinkedListEntryType), pointer :: next => null()
    end type

contains

    subroutine NewImpl(self)
        type(LinkedListType), intent(out) :: self

        nullify(self%first) 
    end subroutine

    subroutine DeleteImpl(self)
       type(LinkedListType), intent(inout) :: self

       if (.not. associated(self%first)) return

       current => self%first
       next => current%next
       do
           deallocate(current)
           if (.not. associated(next)) exit
           current => next
           next => current%next
       enddo

    end subroutine

    subroutine AppendImpl(self, value)

       if (.not. associated(self%first)) then
           allocate(self%first)
           nullify(self%first%next)
           self%first%value = value
           return
       endif


       current => self%first
       do
           if (associated(current%next)) then
               current => current%next
           else
             allocate(current%next)
             current => current%next
             nullify(current%next)
             current%value = value
             exit
           endif
       enddo

    end subroutine

end module

注意:现在已经过了午夜,我不太喜欢在浏览器窗口中编写代码。这段代码可能无法正常工作,只是一个布局。

使用方法如下

program foo
   use LinkedListModule
   type(LinkedListType) :: list

   call New(list)
   call Append(list, 3)
   call Delete(list)
end program

1
太好了,DeleteImpl方法正是我在寻找的。这个面向对象的Fortran多么漂亮整洁啊。 - EMiller
1
@emiller:它不是面向对象的。它是面向对象风格的。 - Stefano Borini
“Append” 会从头到尾遍历整个列表,因此效率非常低。最好是跟踪尾节点并将新节点附加到它上面。为什么要区分 LinkedListTypeLinkedListEntryType - Michel Fioc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接