• No results found

Be attentive to the particular standard specifications regarding argu- argu-ments possessing either the pointer or the target attribute

In document Fortran (Page 86-93)

Programming Principles

55. Be attentive to the particular standard specifications regarding argu- argu-ments possessing either the pointer or the target attribute

Using dummy and actual arguments that possess either thepointerortarget attribute can be confusing. To clarify their use, this rule explains the program behavior when a dummy argument possesses thepointerattribute, and Rule 56 details the behavior when it possesses thetargetattribute.

The explanation is first divided into two major sections: the first when the dummy argument has the pointerattribute, the second when it is assigned solely to the actual argument. In several instances, the behavior the standard prescribes for arguments that are pointers apply to those that are allocatable too. This is pointed out in the text. Short code sections provide examples.

Dummy Pointer Argument An explicit interface to a subprogram must be provided if one or more of its arguments is either a pointer or has the allocatable attribute assigned to it. The actual argument must also be a pointer and all its non-deferred type parameters and ranks shall agree with those of the dummy argument.

In the following code, a parameterized derived type is defined (see Rule 125);

two pointers of this type are declared; and the interfaces of two subroutines, each having two dummy pointer arguments of this type, are given. The explicit interfaces are specified using interface blocks. However, it is normally preferable to have the explicit interface specifications come directly from the procedures themselves – either by residing in the same module as the caller, or from “use association” from another module. Three calls to these routines are shown, and comments within the code explain which are legal calls and which are not.

i n t e g e r , parameter : : MAX LEN = 100 type , p u b l i c : : m y t y p t ( a r r l e n )

i n t e g e r , l e n : : a r r l e n = MAX LEN i n t e g e r : : i n t a r r a y ( a r r l e n ) end t y p e m y t y p t

! d e f i n e t h r e e v a r i a b l e s o f t y p e m y t y p t . one w i t h a

! d e f e r r e d t y p e p a r a m e t e r and two w i t h o u t . t y p e ( m y t y p t , a r r l e n = : ) , p o i n t e r : : d e f v a r

t y p e ( m y t y p t , a r r l e n =50) , p o i n t e r : : n o n d e f v a r 5 0 t y p e ( m y t y p t , a r r l e n =20) , p o i n t e r : : n o n d e f v a r 2 0 i n t e r f a c e

s u b r o u t i n e S u b a ( a r g a 1 , a r g a 2 ) i m p o r t : : m y t y p t

t y p e ( m y t y p t , a r r l e n =50) , i n t e n t ( i n out ) , &

p o i n t e r : : a r g a 1

t y p e ( m y t y p t , a r r l e n = : ) , i n t e n t ( i n out ) , &

p o i n t e r : : a r g a 2 end s u b r o u t i n e S u b a end i n t e r f a c e

! t h i s c a l l i s l e g a l :

! t h e t y p e p a r a m e t e r o f t h e f i r s t a c t u a l a r g u m e n t

! i s n o t d e f e r r e d and i t a g r e e s w i t h t h a t o f t h e dummy

! a r g u m e n t . t h e s e c o n d a c t u a l a r g u m e n t h a s a d e f e r r e d

! t y p e p a r a m e t e r , a s d o e s t h e dummy a r g u m e n t . c a l l S u b a ( n o n d e f v a r 5 0 , d e f v a r )

! t h i s c a l l i s i l l e g a l :

! t h e f i r s t a c t u a l a r g u m e n t h a s a d e f e r r e d t y p e

! p a r a m e t e r b u t t h e f i r s t dummy a r g u m e n t d o e s not ,

! and t h e s e c o n d a c t u a l a r g u m e n t d o e s n o t h a v e a

! d e f e r r e d t y p e p a r a m e t e r b u t t h e s e c o n d dummy

! a r g u m e n t d o e s .

c a l l S u b a ( d e f v a r , n o n d e f v a r 5 0 )

! t h i s c a l l i s i l l e g a l :

! t h e non−d e f e r r e d type parameter o f the f i r s t

! a c t u a l a r g u m e n t d o e s n o t a g r e e w i t h t h e t y p e

! p a r a m e t e r o f t h e f i r s t dummy a r g u m e n t . c a l l S u b a ( n o n d e f v a r 2 0 , d e f v a r )

Attention must be paid to the intent of the dummy argument when it is a pointer; the intent affects the behavior as explained in the next three sections coveringintent (out), intent (in), andintent (in out).

intent (out)

If the dummy argument has this attribute, the pointer association of the actual argument becomes undefined when the procedure is invoked. After the procedure has completed, the association status of the actual argument acquires that given the dummy argument during execution of the procedure (see Rule 53). The behavior on invocation is a potential source of memory leaks, a situation where the program loses access to memory without deal-locating it, so you must be cautious in this case. Here is the interface of a subroutine with such a dummy argument:

! on i n v o c a t i o n o f t h i s p r o c e d u r e , t h e a c t u a l

! a r g u m e n t a s s o c i a t e d w i t h dummy a r g u m e n t

! i n t a r g 1 a c q u i r e s a s t a t u s o f u n d e f i n e d . To u s e

! i t , t h e p r o c e d u r e f i r s t n e e d s t o a l l o c a t e i t

! ( o r i t may be n u l l i f i e d ) . i n t e r f a c e

s u b r o u t i n e S u b a ( i n t a r g 1 )

i n t e g e r , i n t e n t ( out ) , p o i n t e r : : i n t a r g 1 ( : ) end s u b r o u t i n e S u b a

end i n t e r f a c e

Here is a code that includes a call to the procedure. It will cause a memory leak.

i n t e g e r , p o i n t e r : : i n t p t r ( : ) i n t e g e r : : a l l o c s t a t , n u m e l e m s

! a l l o c a t e memory f o r t h e i n t e g e r p o i n t e r a l l o c a t e ( i n t e g e r : : i n t p t r ( n u m e l e m s ) , &

s t a t = a l l o c s t a t )

! I f t h e a l l o c a t i o n i s s u c c e s s f u l , c a l l S u b a .

! a c c e s s t o t h e memory j u s t a l l o c a t e d i s l o s t . i f ( a l l o c s t a t == 0 ) c a l l S u b a ( i n t p t r )

Assigning a pointer dummy argument could be an alternative to returning a pointer as a function result. For example, you may have a linked list of a derived type, and you wish to create a new node in the list (the definition of typemy type tis not shown).

t y p e n o d e t

t y p e ( m y t y p e t ) : : m y t y p e v a l u e t y p e ( n o d e t ) , p o i n t e r : : n e x t n o d e p t r end t y p e n o d e t

s u b r o u t i n e C r e a t e n o d e ( t h i s , m y t y p e o b j e c t ) t y p e ( n o d e t ) , i n t e n t ( out ) , p o i n t e r : : t h i s t y p e ( m y t y p e t ) , i n t e n t ( i n ) : : m y t y p e o b j e c t i n t e g e r : : a l l o c s t a t

! t h e n u l l i f i e d s t a t u s o f t h i s on r e t u r n

! i n d i c a t e s an e r r o r . n u l l i f y ( t h i s )

! c h e c k v a l u e s o f t h e c o m p o n e n t s o f t h i s ;

! p r o c e e d i f c o r r e c t .

i f ( C h e c k c o m p o n e n t s ( m y t y p e o b j e c t ) == 0 ) then

a l l o c a t e ( n o d e t : : t h i s , s t a t= a l l o c s t a t ) i f ( a l l o c s t a t == 0 ) then

t h i s%m y t y p e v a l u e = m y t y p e o b j e c t e l s e

! . . . h a n d l e e r r o r c o n d i t i o n end i f

end i f

end s u b r o u t i n e C r e a t e n o d e

A “dangling” pointer is the result of deallocating the target of a pointer without directly using the pointer itself. To prevent a dangling pointer in the previous calling procedure, you would want to make sure the actual argument that corresponds with argument this is not already associated with a target. (It is too late to do so in Create node because the actual argument has acquired a status of undefined on entry.) In the sample code here, this is accomplished by a call to a procedure named Destroy (not shown).

t y p e ( m y t y p e t ) : : m y t y p e o b j e c t t y p e ( n o d e t ) , p o i n t e r : : n e w n o d e

n u l l i f y ( n e w n o d e )

! c o d e t o s e t c o m p o n e n t s o f m y t y p e o b j e c t .

! c o d e t h a t p o s s i b l y c o u l d a l l o c a t e , a s s i g n ,

! and u s e n e w n o d e .

i f ( a s s o c i a t e d ( n e w n o d e ) ) c a l l D e s t r o y ( n e w n o d e ) c a l l C r e a t e n o d e ( new node , m y t y p e o b j e c t )

intent (in)

The procedure cannot change the association of the pointer to its target during execution. It can, however, change the value of the pointer’s target.

Here is an example:

s u b r o u t i n e C a l c t e m p ( t h i s , t e m p p o i n t e r ) t y p e ( t e m p t ) , i n t e n t ( i n out ) : : t h i s

r e a l , i n t e n t ( i n ) , p o i n t e r : : t e m p p o i n t e r r e a l , t a r g e t : : l o c a l t a r g e t

! The f o l l o w i n g c o d e i s l e g a l : t e m p p o i n t e r = 5 . 2

! b u t t h e f o l l o w i n g two l i n e s o f c o d e a r e n o t : n u l l i f y ( t e m p p o i n t e r )

t e m p p o i n t e r => l o c a l t a r g e t end s u b r o u t i n e C a l c t e m p

This applies not only to dummy arguments that are pointers, but also to dummy arguments of derived type that are not pointers but have pointer components.

type , p u b l i c : : e l e m e n t t r e a l , p o i n t e r : : i n t e n s i t y end t y p e e l e m e n t t

s u b r o u t i n e P r o c e s s e l e m e n t ( t h i s ) t y p e ( e l e m e n t t ) , i n t e n t ( i n ) : : t h i s

! The f o l l o w i n g c o d e i s c o r r e c t : i f ( a s s o c i a t e d ( t h i s%i n t e n s i t y ) ) &

t h i s%i n t e n s i t y = 0 . 0

! b u t t h i s i s n o t :

i f ( a s s o c i a t e d ( t h i s%i n t e n s i t y ) ) &

n u l l i f y ( t h i s%i n t e n s i t y ) end s u b r o u t i n e P r o c e s s e l e m e n t

A further restriction is that the actual argument in a call to a procedure where the corresponding dummy argument is a pointer withintent (in)(or intent (in out)) must be a pointer and not the result of a call to a function that returns a pointer. The following code snippet shows the interface of two calls followed by an illegal reference to the second:

i n t e r f a c e

f u n c t i o n C l o n e e l e m e n t ( t h i s ) r e s u l t ( r e t u r n v a l u e ) t y p e ( e l e m e n t t ) , i n t e n t ( i n ) : : t h i s

t y p e ( e l e m e n t t ) , p o i n t e r : : r e t u r n v a l u e end f u n c t i o n C l o n e e l e m e n t

end i n t e r f a c e . . .

i n t e r f a c e

s u b r o u t i n e A s s e m b l e e l e m e n t ( t h i s )

t y p e ( e l e m e n t t ) , p o i n t e r , i n t e n t ( i n out ) : : t h i s end s u b r o u t i n e A s s e m b l e e l e m e n t

end i n t e r f a c e . . .

t y p e ( e l e m e n t t ) : : e l e m e n t 1

! i l l e g a l c a l l !

c a l l A s s e m b l e e l e m e n t ( C l o n e e l e m e n t ( e l e m e n t 1 ) )

intent (in out)

When the pointer dummy argument has the intent ofintent (in out), both the value and the association of the dummy argument can be changed. On entry to the called subprogram, the dummy pointer argument becomes

associated with the target of the actual pointer argument if it has one. If the dummy pointer becomes associated with a different target during execution, the actual target will be associated with it when control is returned to the invoking routine. Care must be taken, however, if the dummy argument is associated with a local target that ceases to exist on exit. In that case, the actual argument is undefined when execution returns to the calling routine.

The following program demonstrates how this works. It contains a module with a subroutine that has two pointer arguments withintent (in out). In it, one of the arguments, i arg a, is associated with a module variable that has thesaveattribute. Argument int arg b, the second dummy argument, is associated with a variable local to the subroutine that does not have this attribute. The code in the main program that follows shows a call to subroutine Point arg . Comments embedded in the code point out the program behavior.

Listing 6.3: Program Point intent in out module Proc mod

i m p l i c i t none p r i v a t e

p u b l i c : : P o i n t a r g

i n t e g e r , t a r g e t , s a v e : : m o d u l e s a v e d i n t c o n t a i n s

s u b r o u t i n e P o i n t a r g ( i a r g a , i n t a r g b ) i n t e g e r , i n t e n t ( i n out ) , p o i n t e r : : i a r g a i n t e g e r , i n t e n t ( i n out ) , p o i n t e r : : i a r g b i n t e g e r , t a r g e t : : l o c a l n o n s a v e d i n t m o d u l e s a v e d i n t = 50

l o c a l n o n s a v e d i n t = 60 i a r g a => m o d u l e s a v e d i n t i n t a r g b => l o c a l n o n s a v e d i n t end s u b r o u t i n e P o i n t a r g

end module Proc mod

program P o i n t i n t e n t i n o u t use Proc mod , o n l y : P o i n t a r g i m p l i c i t none

i n t e g e r , t a r g e t : : i n t a , i n t b

i n t e g e r , p o i n t e r : : i n t p o i n t a , i n t p o i n t b i n t a = 5

i n t b = 8

i n t p o i n t a => i n t a i n t p o i n t b => i n t b

c a l l P o i n t a r g ( i n t p o i n t a , i n t p o i n t b )

! i n t p o i n t a i s now a s s o c i a t e d w i t h s a v e d module

! v a r i a b l e m o d u l e s a v e d i n t i n module p r o c m o d .

! I t s v a l u e i s 50 ( t h e v a l u e o f i n t a r e m a i n s 5 ) . i f ( a s s o c i a t e d ( i n t p o i n t a ) ) p r i n t * , &

” i n t p o i n t a : ” , i n t p o i n t a

! Even t h o u g h i n t p o i n t b a p p e a r s a s s o c i a t e d ,

! i t s t a r g e t i s u n d e f i n e d ; any r e f e r e n c e t o i t i s

! i l l e g a l .

i f ( a s s o c i a t e d ( i n t p o i n t b ) ) p r i n t * , &

” i n t p o i n t b : ” , i n t p o i n t b end program P o i n t i n t e n t i n o u t

When this program was built using version 5.3 of the Numerical Algorithm Group compiler, the results of executing the program are:

int_point_a: 50

Runtime Error: point-intent-in-outP.f90, line 42: Dangling pointer INT_POINT_B used as argument to intrinsic function ASSOCIATED Target was RETURNed from procedure

PROC_MOD:POINT_ARG

Program terminated by fatal error

Actual Pointer Argument An actual argument may be a pointer even if the dummy argument is not. In this case, the actual argument must be allocated prior to the procedure reference; you can regard this as if the associated target were the actual argument and not the pointer. (An actual argument that has the allocatableattribute must also be allocated if the dummy argument is not also allocatable.) In the following code, the two calls toSub ahave the same effect on the values of both int ptr and int targ; either could be used.

i n t e g e r , p o i n t e r : : i n t p t r i n t e g e r , t a r g e t : : i n t t a r g i n t e r f a c e S u b a ( i n t a r g )

i n t e g e r , i n t e n t ( i n out ) : : i n t a r g end i n t e r f a c e S u b a

i n t t a r g = 5 . 2 i n t p t r => i n t t a r g

! e i t h e r o f t h e f o l l o w i n g two c a l l s c o u l d be made . c a l l S u b a ( i n t p t r )

c a l l S u b a ( i n t t a r g )

56. Be attentive to the particular standard specifications regarding

In document Fortran (Page 86-93)