Smart-Pointers is a reference-counting utility that prevents some common problems associated with unencapsulated pointers, e.g., dangling pointers and memory leaks. In the most common use case, a user type extends the sp_smart_pointers_t type with a child type that encapsulates a pointer associated with a user object. The non-abstract extended type inherits an obligation to define a free procedure that the Smart-Pointers utility ensures will be invoked if and only if all references to the user object go out of scope. See the example here for a demonstration of the intended use case.
Smart-Pointers 2.2.0 is the first release that is fully supported by gfortran. Currently, the use of Smart-Pointers with gfortran requires building gfortran from source until GCC 13 releases. Instructions for building gfortran from source using the OpenCoarrays installer are in the Smart-Pointers release notes.
Obviously, when writing a language interpreter, a memory pool with garbage collection is the right way, but I wanted to put the reference counting to test at the time.
A suggestion given your example suggests the "free"ing is left up to the child type i.e., the user encapsulation and the example shows a single situation toward a scalar instance of the type: can your documentation include some guidance on the "free"ing and how to author the procedure(s) and perhaps your recommendation? Say perhaps an elemental procedure, maybe impure if the user seeks IO logging as part of the "free"ing?
! [ ] denote optional
.
interface
module [impure] elemental subroutine free(self)
implicit none
class(user_object_ptr_t), intent(inout) :: self
end subroutine
end interface
.
end module
submodule( .. ) ..
.
module procedure free
if (associated(self%ref)) then
deallocate(self%ref)
nullify(self%ref)
[ print *,"free(): user_object deallocated" ]
end if
end procedure
Or, once you consume such a type more in codes and gain user feedback, you can consider redesigning the architecture with better finalization schemes?
And I will suggest keeping an eye on the further use cases that develop such that proposal(s) toward language advancement can be developed. The standard you will note has barely scratched the surface on the needs of practitioners even in scientific and technical computing domain toward effective realization of smart types in their codes e.g., those one that follow safe resource encapsulation (a la RAII). Your work is here after all an instance of the need for such smart types.
@VladimirF thanks for your interest. Because this library is based on some recently refactored old code, my memory of some details is rusty. My initial testing suggests that Smart-Pointers does not properly handle circular pointer associations. I tested by editing the user_object_smart_pointer example, adding a new line smart_pointer_1 = smart_pointer_2 immediately after the line smart_pointer_2 = smart_pointer_1. It appears the object doesn’t get freed a the end of the program.
In case it’s helpful, in the top-level README.md file in Smart-Pointers, reference 1 and section 5.2.1 of reference 2 describe how to trigger recursive finalization of a circular linked list. Assuming what you want can be thought of as a circular linked list, the approach described in reference 2 might solve your problem. In fact, I think the code in Figure 5.2 of reference 2 was a precursor to what is in Smart-Pointers, which makes me think that either that code might hint at how to enhance Smart-Pointers to handle circular references or at a minimum, I could add an updated and generalized version of the Figure 5.2 code to Smart-Pointers to support circular references.
If you have any suggestions for how to handle the circular case, a pull request is welcome.
@FortranFan thanks for this great idea. A quick experiment indicates that after prefixing free_interface in “src/smart_pointer/sp_resource_m.f90” with impure elemental and correspondingly prefixing free in “user_object_smart_pointer.f90” with impure elemental, the example code still runs correctly. However, doing so breaks several tests. I’m probably not going to have much use for this code in my own work because I rarely use pointers and almost never allocate memory via pointers so I don’t expect that I’ll look much further into this, but a pull request is always welcome.
I do not have a good solution. I used to use weak references, which did not increase the count, for closing the loops, but it is not an automatic solution.