As a practical matter, it is because allocatable arrays are typically allocated on the heap and automatic arrays on the stack. So the copy from automatic to allocatable would require the deep memory copy. However, the heap to heap copy is not required, a compiler could optimize away that copy with something like an implicit move_alloc() operation, a shallow copy.
It is not allowed to use a function result as the FROM argument in move_alloc(). If it were, that might be a way for the programmer to specify the correct desired behavior.
So given that restriction, I think the safest ways to avoid the redundant allocation are:
-
use a subroutine where you explicitly allocate the arguments yourself.
-
use a subroutine that allocates its dummy argument, and then use
move_alloc()in the calling program to transfer the allocation as necessary.
As a separate issue, there is some ambiguity in the standard regarding an assignment like
a = b
deallocate(b)
where both a(:) and b(:) are allocatable. The deallocate() can be implicit, e.g. if the assignment is the last reference to the local b(:). I think the ambiguity is intentional, in order to allow the compiler to optimize the memory allocation, but the ambiguity has some consequences. If a(:) is allocated and a different size from b(:), then a(:) should be reallocated upon assignment, the contents of b(:) should be copied, and then b(:) should be deallocated. Any pointers to the targets a(:) and b(:) become undefined. The ambiguity is when a(:) is allocated and is the same size as b(:). In this case, one of two things can occur. One thing is that the contents of b(:) are copied to the existing array a(:) and then b(:) is deallocated; pointers to a(:) remain associated, and pointers to b(:) become undefined. But another thing that can occur is that the compiler can move_alloc(from=b,to=a). That is more efficient because no memory copy occurs, it is a shallow copy. However, pointers to the original a(:) would become undefined, and pointers to the original b(:) would be associated with the new a(:).
The programmer can prevent the implicit move_alloc() from occurring, but it is clunky. For example:
if(size(a)==size(b)) then
a(:) = b
else
a = b
endif
A programmer would not normally do that, so some care is necessary when a(:) and/or b(:) are targets and the simple assignment a=b occurs. And if the programmer wants the shallow copy, then he must use move_alloc(), he can’t depend on the compiler alone to recognize the short cut.
The language standard could be modified so that the a(:)=b semantics is required (rather than just optional) when the sizes match, but that would prevent the possibility of this particular memory optimization from occurring.