- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Chapter 14 of Metcalf, Reid and Cohen describes the following code sample ("Figure 14.5"):
module lib_code
use iso_c_binding
type :: pass
integer :: n
real, allocatable :: a(:)
: ! more stuff
end type pass
type(pass), pointer :: struct
contains
subroutine initialize(n, data) bind(c)
integer(c_int), value :: n
type(c_ptr), intent(out) :: data
allocate(struct)
struct%n = n
allocate (struct%a(n))
data=c_loc(structt)
end subtouine initialize
subroutine add(data, ...) bind(c)
type(c_ptr), intent(in) :: data
:
call c_f_pointer(data, struct)
:
end subroutine add
end module lib_code
...and comments:
"When the C code calls initialize, it passes the size. The Fortran code allocates a structure and inside it stores the size and allocates an array component; it then returns a pointer to the structure. The C code later calls add and passes additional data together with the pointer that it received from initialize. The Fortran procedure add uses c_f_pointer to establish a Fortran pointer for the relevant structure. Note that C may call initialize several times if it wishes to work simultaneously with several problems; each will have a separate structure of type pass and be accessible through its own 'handle' of type (c_ptr)."
Well and good; the explanation is clear enough, and this is exactly what I want to do. Looking at the code, though, makes me feel uneasy, as it's not obvious (a) how the compiler ensures that memory occupied by a previously-defined pointer is not overwritten, as no variables here have the 'save' attribute, or (b) assuming that they are somehow automatically saved, how then does one deallocate them later and so avoid a memory leak? Will a simple deallocate(struct) do the trick?
In C++ and other languages, this situation is a little clearer because one creates a named object, based on a class, one can store the object (or a pointer to it) in an array, and knows to call the object destructor when one is done. Here, things don't look so safe:I picture a number ofdisembodied structs floating around in memory with nothing to keep track of them except some handles that, one hopes, the C application is looking after properly.
Am I being too pessimistic here, or are there some other elements I need to add to the template to ensure that nothing gets overwritten or lost?
Thank you,
Stephen.
1 Solution
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - eos pengwern
So I guess that in this case, as the pointer that has been allocated resides in the module rather than in the 'initialize' subroutine, it stays allocated until explicitly deallocated just like an allocatable array would if held in the module.
I might be missing something here - but the "struct" fortran pointer (it is not an allocatable) being at module scope is not relevant - you could (should? see below) have it as a local variable of each subroutine and you would get the same behaviour. I think the only reason its been put at module scope here is that it saves a bit of typing.
I'd prefer "type(pass), pointer :: struct" local to each routine simply because that's the appropriate scope for the lifetime of the information that's associated with that variable. I also strongly suspect a module scope variable would have issues if this code was ever used in a multi-threaded situation, without additional code, but I don't play in that park.
Each time you call allocate on a pointer, you get a new object, in new storage. If you want to lose/leak memory, there's nothing stopping you. This is different to objects with the allocatable attribute. There's no automatic clean-up/deallocate for pointers either - the programmer needs to look after that (though I think a vendor could offer this as an extension?). The analogy with c++ is a pointer to an object allocated with new and then nuked with delete.
So normally this sort of setup would have an uninitialise/delete/destruct/free/release function that calls DEALLOCATE. For every time you "C" client code calls initialise, it must eventually call this cleanup function or the allocated object will sit around until the program terminates.
The attached might be of interest. It is not necessarily compilable/runable, but hopefully still useful. Interested in any alternative approaches you might have.
Edit: to fix file attachment problem.
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
According to Fortran 95 standard, allocatable arrays/objects are deallocated automatically at subroutine exit, when they go out of scope. For the previous 5 years, it was necessary to deallocate explicitly. You are entitled to deallocate explicitly if you wish. The Fortran system is entitled also to deallocate other local variables which don't have SAVE declarations, as a C compiler would do with auto variables.
If you had SAVE variables and called multiple concurrent instances of the subroutine, you would have a storage clash, analogous to C static variables.
If you had SAVE variables and called multiple concurrent instances of the subroutine, you would have a storage clash, analogous to C static variables.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - tim18
According to Fortran 95 standard, allocatable arrays/objects are deallocated automatically at subroutine exit, when they go out of scope. For the previous 5 years, it was necessary to deallocate explicitly. You are entitled to deallocate explicitly if you wish. The Fortran system is entitled also to deallocate other local variables which don't have SAVE declarations, as a C compiler would do with auto variables.
If you had SAVE variables and called multiple concurrent instances of the subroutine, you would have a storage clash, analogous to C static variables.
If you had SAVE variables and called multiple concurrent instances of the subroutine, you would have a storage clash, analogous to C static variables.
So I guess that in this case, as the pointer that has been allocated resides in the module rather than in the 'initialize' subroutine, it stays allocated until explicitly deallocated just like an allocatable array would if held in the module.
Presumably, the fact that 'struct' is a pointer, and there is no static variable of type(pass) defined, is the mechanism that lets the compiler avoid overwriting the same 'struct' over and over again. I haven't used pointers like this before; normally I create a bunch of allocatable arrays, and create a pointer to point at one of them. If I then try to allocate an array that has already been allocated, I get an 'already allocated' error message. The concept of being able to allocate multiple structures with the same name but different pointers is unfamiliar, butI can see its very powerful.
Stephen.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - eos pengwern
So I guess that in this case, as the pointer that has been allocated resides in the module rather than in the 'initialize' subroutine, it stays allocated until explicitly deallocated just like an allocatable array would if held in the module.
I might be missing something here - but the "struct" fortran pointer (it is not an allocatable) being at module scope is not relevant - you could (should? see below) have it as a local variable of each subroutine and you would get the same behaviour. I think the only reason its been put at module scope here is that it saves a bit of typing.
I'd prefer "type(pass), pointer :: struct" local to each routine simply because that's the appropriate scope for the lifetime of the information that's associated with that variable. I also strongly suspect a module scope variable would have issues if this code was ever used in a multi-threaded situation, without additional code, but I don't play in that park.
Each time you call allocate on a pointer, you get a new object, in new storage. If you want to lose/leak memory, there's nothing stopping you. This is different to objects with the allocatable attribute. There's no automatic clean-up/deallocate for pointers either - the programmer needs to look after that (though I think a vendor could offer this as an extension?). The analogy with c++ is a pointer to an object allocated with new and then nuked with delete.
So normally this sort of setup would have an uninitialise/delete/destruct/free/release function that calls DEALLOCATE. For every time you "C" client code calls initialise, it must eventually call this cleanup function or the allocated object will sit around until the program terminates.
The attached might be of interest. It is not necessarily compilable/runable, but hopefully still useful. Interested in any alternative approaches you might have.
Edit: to fix file attachment problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, IanH, that's really useful. I was interested bythe MATLAB example (your attached .m files - although I'm afraid that DLLReference.m wouldn't open) as well; I'm still working with an older version of MATLAB which doesn't support classes yet, but you've provoked me to look up what's available in thecurrent version and it actually looks very capable.
Stephen.
Stephen.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page