2015-11-25 36 views
2

在以下代碼中的可分配數組,我試圖通過首先分配較大尺寸的臨時數組buf(:),複製的a(:)內容以buf(:),然後使用move_alloc()到增加的a(:)長度從buf數組描述符複製到a擴展與MOVE_ALLOC和源分配

program main 
    implicit none 
    integer, allocatable :: a(:), buf(:) 

    allocate(a(2)) 
    a = [1,2] 

    allocate(buf(4), source= 0)  !! (1) 
    buf(1:2) = a(1:2)    !! (2) 

    ! allocate(buf(4), source= a) !! (3) 

    ! deallocate(a)     !! (4) 
    call move_alloc(buf, a) 

    print *, "a(:) = ", a(:) 
end 

在這裏,我有兩個問題:第一,在第4行,是有必要呼籲move_alloc()之前明確取消分配a(:) ...?即使沒有4號線,gfortran和英特爾Fortran似乎也能正常工作,但是這是否意味着move_alloc()會自動解除分配a(:)的預分配?其次,我們可以用3替換第1行和第2行,即使用不同長度數組的源代碼分配?我已經做了實驗,再一次,gfortran和英特爾Fortran似乎都以(顯然)正確的結果接受它。

+0

還有'a = [a,0,0]'來達到終點的另一種方式。 – francescalus

+0

[除了缺少''''和'i'的聲明]最終表達式沒有問題。源項是一個通用表達式(有一些限制 - 鬆散地,不依賴於被分配的東西),一次和最初評估。 – francescalus

+0

我嘗試過'allocate(buf(4),source = [a,0,0])'和'allocate(buf(4),source = [a,(0,i = 3,4)])''並且都工作正常(沒有運行時錯誤和正確的結果)。這種用法似乎非常靈活並且可能有用... – roygvib

回答

3

是不同於Fortran標準(2008年,13.7.118)約move_alloc我們有參數to(子程序的第二個參數)的細節

它是一個INTENT(OUT)參數

,它與您在gfortran manual的鏈接中給出的描述相匹配。

至於與intent(out)allocatable任何其他僞參數與屬性相關聯to實際參數,然後,被釋放上調用子程序move_alloc。也就是說,你不需要自己釋放a

關於採購的分配,我們already know是被分配數組必須迎合與源陣列,這樣寫

allocate(buf(4), source=a) ! a is the same rank as buf, but extent 2 

是無效的,絲毫不亞於

allocate(buf(4), source=a(1:2)) 

是。

然而,雖然有一些關於來源分配的編號約束條件,但這種一致性要求並不具有其中一種約束條件。所以,你的編譯器不需要檢測你的代碼是不符合的。

當然,編譯器允許抱怨,正如您在使用a(1:2)作爲源時看到的那樣。在某種程度上,在編譯時看到一系列範圍4與的情況不符合a(1:2)要容易得多。您可以嘗試使用a(1:SIZE(a))來查看編譯器在此類測試中所付出的努力。

作爲最後的評論,當然,一個可以用單源分配更換你的線1和2:

allocate(buf, source=[a,0,0]) ! Buf is 2 longer than a 

但是,這未必是「好」。

+0

@francescalus非常感謝您的詳細解釋。我不知道如果一個虛擬參數同時具有ALLOCATABLE和INTENT(OUT),實際參數將自動釋放(如有必要)。事實上,這是我第一次遇到這種情況,因爲我只使用ALLOCATABLE虛擬變量來分配尚未分配的數組(在我的其他程序中)。 – roygvib

+0

至於源代碼分配,我在閱讀你的解釋之後嘗試了其他幾種模式。首先,我用'gfortran -fcheck = all'編譯了'allocate(buf(4),source = a)',然後給出了有關數組邊界的運行時錯誤。所以看起來allocate()試圖讀取(3)和(4)將它們複製到buf(3:4)。另一方面,'ifort -check all'沒有爲'source = a'(顯然爲buf(3:4)填0)的運行時錯誤,所以對於這個不符合的代碼,行爲似乎不同。 – roygvib

+0

接下來,對於'allocate(buf(4),source = a(1:size(a)))'和'allocate(buf(4),source = a(:))',ifort沒有任何抱怨沒有給出任何選項,但是當指定了全選時,它給出了運行時錯誤。 gfortran的行爲也類似(使用-fcheck = all時引起的運行時錯誤)。所以這與超出數組邊界的問題基本相同......所以我想我現在理解了這種行爲。非常感謝:) – roygvib

1

是否有必要取消分配a(:)

更新我誤解你的問題。您在詢問TO部分。

我剛試了一下valgrind,好像deallocate沒有必要防止泄漏。但我可能仍然會這樣做,只是爲了安全起見。

第二個問題:

使用數組的長度不同

[我們能否] ...使用來源分配?

根據我的可信Fortran Book,無:

[該] ...被分配必須迎合以陣列(具有相同的秩和形狀)源陣列或表達。

話又說回來,我的書不包括2003年以後的標準,這樣的事情可能會爲2008年的Fortran或Fortran的2015年

+0

非常感謝您的信息。是的,我在詢問TO部分。我檢查了gfortran的[手冊頁](https://gcc.gnu.org/onlinedocs/gfortran/MOVE_005fALLOC.html),但沒有足夠的信息。所以我害怕內存泄漏......我還發現英特爾的[頁面](https://software.intel.com/zh-cn/node/526469),其中說TO部分已被釋放,但有時ifort是太慷慨了,所以我想知道它是否也是其他編譯器的常見行爲。 – roygvib

+0

至於源代碼分配,我也嘗試過類似'allocate(buf(4),source = a(1:2))',但是這兩個編譯器都抱怨數組的形狀不同。有趣的是,爲什麼編譯器不會在源代碼部分沒有使用冒號時引發錯誤... – roygvib

2

Fortran標準的編寫使您不必爲可分配內存泄漏而苦惱。如果操作不是首先被禁止的,它不應該導致任何泄漏。該規則適用於可分配變量的任何可能的標準符合操作。

因此,正如英特爾手冊所述,to參數將首先解除分配。

+0

它可能會用於某人,但franvescalus的答案更嚴格。我的離職是作爲提供信息。在他的答案出現之前,我開始寫這篇文章。 –

+0

非常感謝您的信息。我認爲這樣可以確保沒有內存泄漏。假設即使我們在Fortran中使用數組指針,也不會發生泄漏,這還可以嗎?或者它是一個不同的故事,並且上述安全行爲僅適用於可分配陣列...? (我猜後者會是這種情況。) – roygvib

+0

有很多方法可以導致內存泄漏或程序崩潰。他們是一個不同的故事。 –