2013-02-19 18 views
14

Trong ứng dụng của tôi, tôi có ghi lại như sau:Tôi có cần phải hoàn thành mảng bản ghi trong Delphi không?

TTransaction = record 
    Alias: string 
    Description: string 
    Creation: TDateTime 
    Count: Integer 
end; 

và tôi đang sử dụng hồ sơ này trong mảng này:

Transactions = array of TTransaction; 

Tôi đang giữ mảng nạp trong thời gian chạy, nhưng ở một trao thời gian tôi cần phải xóa tất cả dữ liệu và thêm một số dữ liệu mới.

Có đủ chỉ để sử dụng:

SetLength(Transactions, 0); ? 

Hoặc tôi cần phải hoàn thành một cái gì đó?

Trả lời

15

Có ba cách để deallocate công ty liên kết bộ nhớ với một mảng động, a:

SetLength(a, 0); 
Finalize(a); 
a := nil; 

Tùy thuộc vào bạn sẽ sử dụng loại nào.

Các documentation nói giống nhau, mặc dù trong một hơi tròn về thời trang:

Để deallocate một mảng động, chuyển nhượng bằng không cho một biến tham chiếu đến các mảng hoặc vượt qua các biến để Hoàn thiện; một trong các phương thức này phân phối mảng, miễn là không có tham chiếu nào khác. Các mảng động được tự động phát hành khi số lượng tham chiếu của chúng giảm xuống 0.Các mảng động có chiều dài 0 có giá trị là 0.

Điều này sẽ giải phóng tất cả bộ nhớ được liên kết với mảng, bao gồm bất kỳ loại được quản lý lồng nhau nào, chẳng hạn như chuỗi, arrys động, v.v ... thuộc sở hữu của loại bản ghi của bạn.

Nếu bạn cần thay đổi kích thước mảng để sử dụng sau này và có sẵn dữ liệu mới, chỉ cần thay đổi kích thước bằng SetLength và khởi tạo các phần tử còn lại một cách thích hợp.

+1

'Finalize' có thực sự thay đổi giá trị' a' không? Tôi luôn luôn bị ấn tượng vì nó không - nó giải phóng bộ nhớ trong khi để lại địa chỉ ban đầu của mảng động được lưu trữ trong 'a', với dự đoán của một cuộc gọi tiếp theo tới' Free' hoặc 'Initialize'. –

+1

@Rob Đối với mảng động, ba tùy chọn này đều tương đương nhau. Đối với một loại được quản lý, Finalize phải đặt tham chiếu là 0. Nó không có sự lựa chọn. Hãy xem xét một biến cục bộ của mảng động kiểu. –

+0

@DavidHeffernan Trong trường hợp giới hạn cao nhất của mảng là 10, thì tốt hơn nên sử dụng: 1- Đặt thành Nil và tạo lại tất cả. 2 - Liên kết các chỉ mục đã sử dụng với các giá trị tiếp theo? – EProgrammerNotFound

0

SetLength (transactions,0) không phải là một ý kiến ​​hay. Tôi nghĩ cách tốt nhất là khởi động lại tất cả các thành viên của bản ghi. Bằng cách này, bạn giữ biến được tải.

Bạn có thể sử dụng SetLength (transactions,0) nếu bạn không cần biến nữa, để sử dụng ít bộ nhớ nhất có thể. Tất nhiên, nếu bạn cần nó một lần nữa ở đâu đó trong chương trình, bạn có thể điều chỉnh lại độ dài của nó, giả sử bạn biết điều đó.

Bạn không cần phải hoàn thành bất cứ điều gì, beause đó là một bản ghi, không phải là một lớp học. Hồ sơ không có các nhà thầu xây dựng hoặc destructors, như các lớp học.

+0

* "bạn có thể điều chỉnh lại độ dài" * - nhưng hãy nhớ rằng bạn có thể nhận tất cả các mục cũ được sao chép với tất cả nội dung tĩnh và nội dung động (chuỗi, dyn mảng) có thể sẽ có số đếm Tăng giảm. Đó là lý do tại sao tôi sử dụng deallocation mảng đầy đủ trước khi thay đổi độ dài trong một số trường hợp. * "Bạn không cần phải hoàn thành bất cứ điều gì, beause đó là một bản ghi, không phải là một lớp" * - đó là sự thật chỉ khi tất cả các lĩnh vực hồ sơ là các loại đơn giản (không dây/dyn mảng/giao diện). – Fr0sT

10

Đặt độ dài mảng thành 0 sẽ phá hủy mảng, điều này ngược với mong muốn của bạn "giữ cho mảng được tải". Tuy nhiên, nó sẽ giải phóng bộ nhớ cho tất cả các bản ghi và chuỗi của chúng (đối với bất kỳ chuỗi nào có số tham chiếu là 1 tại thời điểm đó).

Nếu bạn chỉ muốn giải phóng bộ nhớ cho các chuỗi, nhưng giữ bộ nhớ bản ghi được phân bổ (vì bạn định phân bổ một bộ bản ghi khác ngay sau đó và bạn không muốn lãng phí việc phát hành và phân bổ lại cùng một bộ nhớ), sau đó bạn có thể xóa chỉ các thành viên chuỗi, nhưng không có cuộc gọi thư viện duy nhất để làm điều đó cho bạn. Thay vào đó, bạn sẽ cần phải viết một vòng lặp và tự xóa từng trường của bản ghi.

for i := 0 to High(transactions) do begin 
    transactions[i].alias := ''; 
    transactions[i].description := ''; 
end; 

Nếu có rất nhiều lĩnh vực trong hồ sơ cần thanh toán bù trừ, sau đó nó có thể là thuận tiện hơn để gán một giá trị mặc định TTransaction để mỗi phần tử của mảng. Bạn có thể sử dụng Default chức năng, hoặc trong các phiên bản cũ của Delphi bạn có thể khai báo một TTransaction đó có tất cả các lĩnh vực của nó rõ ràng đã:

const 
    ClearTransaction: TTransaction = (alias: ''; description: ''; creation: 0; count: 0); 

for i := 0 to High(transactions) do 
    transactions[i] := ClearTransaction; 
    // or 
    transactions[i] := Default(TTransaction); 
+0

Tôi nghĩ rằng đây là cách tốt nhất để làm ... vì người dùng quyết định khi nào anh ta muốn tải lại tất cả dữ liệu, tôi biết rằng các loại bản ghi là cấu trúc và trong trường hợp của tôi về các kiểu nguyên thủy, đây là lý do tôi hỏi. cảm ơn cho câu trả lời – EProgrammerNotFound

+0

Câu hỏi hiện có liên quan đến chủ đề được đề cập trong phần thứ hai của câu trả lời ở đây là: http://stackoverflow.com/questions/11065821/how-to-properly-free-records-that-contain- các loại khác nhau-trong-delphi-at-once –

+0

@DavidHeffernan tôi đọc chủ đề đó và đó là lý do tại sao tôi hỏi về việc hoàn thiện. Tôi đã nhầm lẫn với rất nhiều câu trả lời, và anh chàng nói về hoàn thiện + fillchar ... – EProgrammerNotFound

Các vấn đề liên quan