2013-05-08 31 views
6

Tôi hiện đang cố gắng mã hóa một chương trình con nhỏ ở Fortran để phân bổ tất cả các biến được phân bổ trong bộ nhớ khi chương trình của tôi gặp lỗi, tức là không thể tải tệp hoặc tệp không cần thiết. Tại thời điểm này, thực hiện phải được chấm dứt, nhưng không phải tất cả các allocatables nhất thiết phải được phân bổ (nó phụ thuộc vào nơi trên mã lỗi xuất hiện), vì vậy tôi không thể làm cho một dọn dẹp deallocating tất cả chúng.Fortran DEALLOCATE

cách tiếp cận hiện tại của tôi là như sau:

SUBROUTINE Cleanup(A) 

    REAL(8), ALLOCATABLE, DIMENSION(:) :: A 

    IF (ALLOCATED(A)) THEN 
     DEALLOCATE(A) 
    END IF 

END SUBROUTINE 

và gọi là "Cleanup" cho mỗi allocatable. Vấn đề với điều này là không phải tất cả các biến của tôi là thứ nguyên-1. Tôi có tới ba chiều trong một số trong số chúng.

Lần đầu tiên tôi nghĩ đến việc viết 3 chương trình con khác nhau cho các kích thước khác nhau và sử dụng quá tải, nhưng điều này không có vẻ rất thanh lịch. Sau đó tôi nghĩ rằng có lẽ tôi có thể vượt qua một con trỏ thay vì đối số actuall A, nhưng tôi đã googled và có vẻ như bạn không thể deallocate một biến mục tiêu máng một con trỏ.

Bất kỳ ý tưởng nào về cách thực hiện điều này đúng cách?

Cảm ơn.

+4

Khi thực thi được chấm dứt, tất cả các tài nguyên được mã của bạn sử dụng sẽ tự động được giải phóng theo bất kỳ cách nào, vì vậy bạn không phải lo lắng về việc giải quyết rõ ràng chúng. –

+1

Tôi biết Fortran sẽ tự động giải phóng bộ nhớ, nhưng trong trường hợp này tôi đang viết một dll được gọi từ Labview, vì vậy đây là ai đang quản lý bộ nhớ. Khi dll đến một lỗi, Labview đột nhiên dừng lại, và nếu tôi cố gắng thực hiện lại, nó sẽ hiển thị thông báo: "Array đã được cấp phát" và tắt. Điều này có nghĩa là bộ nhớ không được xử lý đúng cách. – derkomai

+1

Lưu ý: 'thực (8)' không được bảo đảm là 8 byte. Một cách di động là 'sử dụng ISO_FORTRAN_ENV',' real (real64) 'cho 64 bit. –

Trả lời

7

cách tiếp cận của tôi để này sẽ sử dụng một sự kết hợp các nội dung sau:

  • Tính đến Fortran 95, tất cả các biến allocatable un-lưu địa phương được phân bổ khi kết thúc thủ tục sẽ được tự động deallocated. Cho dù điều này được áp dụng phụ thuộc vào cách DLL của bạn được gọi, và do đó cho dù bạn thực sự có thể cấu trúc những thứ như vậy mà tất cả các allocatables của bạn là người dân địa phương chưa lưu.

  • Kể từ Fortran 2003 (hoặc Fortran 95 + TR cấp có thể phân bổ - cấp độ ngôn ngữ này được hỗ trợ rộng rãi trong các trình biên dịch Fortran được duy trì) các đối số thực tế được phân bổ cho các đối số giả định INTENT (OUT) sẽ được tự động deallocated trước khi thủ tục bắt đầu thực hiện . Cleanup thói quen của bạn trong câu hỏi chỉ cần thêm tuyên bố của đối số giả như INTENT (OUT) và sau đó không cần cho các thử nghiệm IF hoặc DEALLOCATE. Bạn vẫn cần phải viết thường trình cho từng loại và thứ hạng mà bạn cần để làm sạch.

  • Tương tự như trước đó, các thành phần có thể phân bổ của biến loại có nguồn gốc được chuyển đến đối số giả INTENT (OUT) sẽ tự động được phân bổ lại. Vì vậy, bạn có thể thu thập tất cả các biến có thể phân bổ của bạn với nhau thành các thành phần trong một đối tượng có nguồn gốc. Dọn dẹp sau đó chỉ đơn giản là liên quan đến việc truyền đối tượng đó đến một thủ tục với một INTENT (OUT) giả. INTENT (OUT) ở đây cũng đặt lại các thành phần có khởi tạo mặc định trở lại giá trị "mặc định" của chúng. Có lẽ có dọn dẹp khác mà bạn cần phải tự làm tại thời điểm này quá (đóng tập tin, vv).

  • Một cách tiếp cận khác, một lần nữa sử dụng các kiểu có nguồn gốc với tất cả các biến của bạn làm thành phần, là làm cho đối tượng kiểu dẫn xuất có thể phân bổ. Khi bạn cần dọn dẹp, chỉ cần deallocate rằng một đối tượng - các thành phần của nó sẽ được tự động deallocated. Fortran 2003 cho phép một thủ tục cuối cùng được kích hoạt từ loại sự kiện này nếu bạn có thêm dọn dẹp khác để làm tại thời điểm này.

Cách tiếp cận kiểu dẫn xuất cũng giúp dễ dàng có nhiều phiên bản của bất kỳ DLL nào hỗ trợ hoạt động độc lập cùng một lúc (bạn chỉ có nhiều đối tượng có nguồn gốc).

Ví dụ về các cách tiếp cận loại hình xuất phát, đưa ra:

TYPE MyType 
    REAL, ALLOCATABLE :: variable_one(:) 
    INTEGER, ALLOCATABLE :: variable_two(:) 
    ... 
END TYPE MyType 

Ý ĐỊNH (OUT) giả

TYPE(MyType) :: object 
ALLOCATE(object%variable_one(xxx)) 
ALLOCATE(object%variable_two(yyy)) 
... 
IF (things_have_gone_wrong) CALL Cleanup(object) 
... 
SUBROUTINE Cleanup(arg) 
    TYPE(MyType), INTENT(OUT) :: arg 
END SUBROUTINE Cleanup 

đối tượng ALLOCATABLE.

TYPE(MyType), ALLOCATABLE :: object 
ALLOCATE(object) 
ALLOCATE(object%variable_one(...)) 
ALLOCATE(object%variable_two(...)) 

... 
IF (things_have_gone_wrong) DEALLOCATE(object) 
+1

Điều đó hoạt động rất tốt, cảm ơn bạn rất nhiều! – derkomai

+2

Một cách khác tôi đã tìm thấy để giải quyết vấn đề này là sử dụng macro Preprocessor: #define Cleanup (A) IF (phân bổ (A)) deallocate (A) Khi được gọi, Cleanup không được công việc. – derkomai