I’ve encountered this problem before, where the finalizer works “earlier” than you expect it too.
type :: holds_pointer
type(c_ptr) :: handle = c_null_ptr ! points to heap memory
contains
final :: shutdown ! releases the handle
procedure :: use_handle
end type
type(holds_pointer) :: instance
instance = create_instance()
call instance%use_handle() ! KA-BOOM! (Invalid handle)
The problem is really not the finalizer, but the fact that object creation, destruction, and copying are tightly linked operations. In C++ they call this the rule of three or “the big three”. Quoting Wikipedia, the rule claims that if a class defines any of the following then it should probably explicitly define all three:
- destructor
- copy constructor
- copy assignment operator
Fortran doesn’t have such a thing as a copy constructor. You could fix the problem by overloading the assignment operator, but this has it’s own subtle problems (i.e. does the assignment perform a deep copy or a shallow copy of the pointer?).
There are (at least) two ways to fix this:
- avoid assignment; use an initalizer subroutine or a type-bound procedure (as shown by @davidpfister) instead
- wrap the pointer in a derived type with defined assignment as explained here: Should we avoid assignment of derived types in robust programs? - #35 by FortranFan