2012-03-11 40 views
11

Đừng bắn tôi, nhưng đây là lần đầu tiên tôi thấy một sử dụng một địa phương ghiconst (Hoặc có thể tôi chỉ cách quá già ...): "The WinAPI way (by Peter Below from TeamB)"Có thể ghi được const địa phương

Hãy nhìn vào địa phương const FullScreen: Boolean = False; và sau đó FullScreen := not FullScreen;

Lúc đầu tôi thoght Đây là một tính năng mới với phiên bản Delphi hiện đại, nhưng nó cũng hoạt động với D5 của tôi. Vì vậy, câu hỏi của tôi là: là hằng số có thể ghi cục bộ là chính xác cùng một như tuyên bố một hằng số ghi toàn cầu?

ví dụ:

procedure TForm1.Button1Click(Sender: TObject); 
Const 
    LocalConst: Boolean = False; 
begin 
    LocalConst := not LocalConst; 
    if LocalConst then Beep; 
end; 

Hoạt động giống như mã này? :

Const 
    GlobalConst_Button2Click: Boolean = False; 

procedure TForm1.Button2Click(Sender: TObject); 
begin 
    GlobalConst_Button2Click := not GlobalConst_Button2Click; 
    if GlobalConst_Button2Click then Beep; 
end; 

Hoặc, LocalConst là địa phương cho phương pháp của nó tức là tĩnh? Chủ đề liên tục này có an toàn không?
Có ai có thể làm sáng tỏ vấn đề này không?

+6

@ user539484 - ngừng giảm giá ẩn danh; Tôi gần như chắc chắn đó là bạn! Tôi đang xem diễn viên bỏ phiếu của bạn. – TLama

Trả lời

11

Mã có hằng số được nhập cục bộ và toàn cầu thực hiện chính xác điều tương tự.

Như David đã tuyên bố biến tĩnh toàn cầu (hay còn gọi là hằng số đã nhập) có thể truy cập được trong suốt chương trình và biến tĩnh cục bộ không được. Dưới đây tôi sẽ tham khảo typed constantsstatic variables bởi vì đó là những gì họ thực sự đang có.

Tuy nhiên, biến tĩnh cục bộ không tồn tại trong bộ nhớ giống hệt như biến tĩnh toàn cục. Nó chỉ là trình biên dịch không cho phép bạn truy cập vào một var cục bộ từ bên ngoài thường trình.
Cũng lưu ý rằng nếu var tĩnh cục bộ của bạn đặc biệt lớn (hoặc bạn có rất nhiều) chúng sẽ ăn một bộ nhớ liên tục (mặc dù tôi không thể quan sát được một trường hợp có thể là vấn đề).

Bởi vì biến tĩnh nằm ở một vị trí cố định, nó không phải là luồng an toàn. Nó có hiệu quả biến thành một biến chia sẻ giữa tất cả các cá thể luồng.
Nếu biến tĩnh không thể thay đổi trong một chu kỳ CPU (nghĩa là nếu nó lớn hơn số nguyên hoặc nếu đó là một kiểu phức) hơn hai luồng có thể thay đổi các phần khác nhau của biến cùng một lúc, thường dẫn đến tham nhũng.

Nó có thể được thay đổi trong một chu kỳ, ví dụ: một boolean hoặc số nguyên hơn bạn không bao giờ có thể biết liệu các chủ đề bạn đang ở là một trong đó thay đổi nó cuối cùng hoặc một số khác đã làm mà sẽ dẫn đến kết quả không thể đoán trước trong hầu hết các trường hợp.

Trong ngắn
Sử dụng các tĩnh tĩnh trong mã luồng là một ý tưởng rất tồi trừ khi bạn biết chính xác mình đang làm gì.

Một ngoại lệ đối với điều này có thể là bộ đếm số nguyên mà bạn chỉ tăng và kiểm tra xem có nhiều hơn x lần thực thi đã xảy ra hay không.
Vữa tĩnh thường không phù hợp để truyền thông điệp giữa các chủ đề.

Nếu bạn muốn chia sẻ dữ liệu giữa các chủ đề đó là một ý tưởng tốt hơn để sử dụng threadvar,
see: http://en.wikipedia.org/wiki/Thread-local_storage
và: https://stackoverflow.com/search?q=delphi+threadvar

Cuối cùng
Có rất ít những vấn đề đòi hỏi vars tĩnh toàn cầu và tốt nhất là tránh vì chúng nguy hiểm.
Vữa tĩnh cục bộ hữu ích trong mã luồng đơn để theo dõi trạng thái giữa các lần thực thi khác nhau của một thường trình.
Chúng vô ích khi thực hiện điều này trong mã đa luồng vì điều kiện chủng tộc.

4

Hằng số có thể ghi cục bộ giống hệt như khai báo hằng số ghi toàn cục không?

Sự khác biệt duy nhất là phạm vi. Biến toàn cục là, tốt, toàn cục và biến cục bộ có phạm vi cục bộ. Hằng số đã nhập có thể ghi là một xấp xỉ hợp lý đối với các biến địa phương tĩnh C.

Những bất lợi lớn của hằng số có thể ghi là không có hỗ trợ từ khóa như trong C và bạn phải sử dụng tùy chọn trình biên dịch để chuyển đổi ý nghĩa của ngôn ngữ! Theo quan điểm của tôi, điều này làm cho hằng số có thể ghi có hiệu quả vô dụng.

+10

Chúc mừng bạn đã đạt được đại diện 100k! Tôi đoán đó là lý do tại sao bạn có những bông hoa! –

+0

Quá xấu phiên bản gốc của câu trả lời này không chính xác. Nhưng cảm ơn! –

+0

@David, Đừng quên * ai * đã làm ya 100k! :-P Chúc mừng! – kobik

4

Tôi hơi muộn cho bữa tiệc, nhưng tôi vẫn muốn thêm một số thông tin về các hằng số có thể ghi.

Trước hết, như Johan và David tuyên bố các hằng số toàn cầu và cục bộ không khác nhau về bộ nhớ.

Đối với những người quan tâm đến việc sử dụng các hằng số có thể ghi: Tôi thấy hữu ích khi mô phỏng chức năng "Hứa hẹn" để làm cho chức năng "Lười biếng". Ofcourse delphi không hỗ trợ Promises, vì vậy đây chỉ là một phần hiệu quả.

Xem xét một hàm để đếm số lượng từ trong một chuỗi:

function CountWords(Input: String):Integer; 
var 
    Worker: TStringList; 
begin 
    Worker := TStringList.Create; 
    Worker.DelimitedText := Input; 
    Result := Worker.Count; 
    Worker.Free; 
end; 

Bây giờ tưởng tượng nó beeing gọi nhiều lần trong chương trình của chúng tôi. Đối tượng TStringList sẽ được tạo ra và giải phóng mỗi khi chúng ta thực hiện nó, do đó làm thêm công việc. Bạn ofcourse thể giải quyết điều này bằng cách tạo ra một Worker_CountWords biến toàn cầu, khởi tạo nó trên đầu chương trình và sử dụng nó trong chức năng của bạn, nhưng hãy xem này:

function CountWords(Input: String):Integer; 
{$J+} //Enable writable constants 
const 
    Worker: TStringList = nil; 
{$J-} //Disable writable constants 
begin 
    if Worker = nil then 
    begin 
    Worker := TStringList.Create; 
    //Other Initialization code here 
    end; 
    Worker.DelimitedText := Input; 
    Result := Worker.Count; 
end; 

Chức năng này sẽ chỉ tạo TStringList lần và sử dụng nó sau này , nhưng sẽ không bao giờ giải phóng nó (một nhược điểm ở đây). Nhưng đối với một chức năng có thể được gọi bất kỳ lúc nào trong khi ứng dụng đang chạy thì đây là loại phù hợp. Điều này có thể làm cho mã của bạn trông sạch hơn một chút nếu bạn sẽ ... Bây giờ, hãy chú ý - đây không thực sự là lời hứa, nhưng nó đạt được kết quả tương tự. Bạn có thể làm điều này với các cuộc gọi hàm (tôi đã thử thay thế hàm thực sự trong bộ nhớ và ý tưởng khá xấu, nhưng bạn có thể tạo một const để giữ con trỏ hoạt động, lúc bắt đầu giữ con trỏ đến hàm khởi tạo và sau đó thay thế cho chức năng công nhân thực tế và chức năng cha mẹ sẽ chỉ có một cuộc gọi đến một chức năng được tổ chức trong một hằng số). Tôi không thể nghĩ ra một ví dụ tốt ngay bây giờ, vì vậy tôi sẽ cho bạn thấy rằng một trong những ngày của riêng bạn.

Ngoài ra nó không phải là cần thiết để có {$ WRITABLECONST ON} để thay đổi giá trị không đổi, bạn cũng có thể làm một cái gì đó như thế này:

procedure DoSomeWork; 
const 
    FirstCall : TDateTime = 0; 
begin 
    if FirstCall = 0 then 
    PDateTime(@FirstCall)^ := Now; 
    Writeln(TimeToStr(FirstCall)); 
    //some actual work here 
end; 

Cùng một điều áp dụng cho const tham số trong chức năng, bởi vì họ là chính xác giống như tham số var (thông qua tham chiếu để tránh dành thời gian tạo biến riêng biệt), khác biệt duy nhất là trình biên dịch không cho phép bạn thay đổi các giá trị này bình thường.

P.S. Hãy cẩn thận với các thông số chức năng const, vì bạn có thể vượt qua các hằng số thực tế như foo(12) và cố gắng sửa đổi điều đó có thể gây rối ...

+0

Chức năng 'CountWords' khác nhau về chức năng đối với một hàm bằng cách sử dụng singleton như thế nào? –

+2

Bí quyết tuyệt vời với 'FirstCall: TDateTime' với' {$ J-} ​​' – kobik

+0

Tôi nghĩ tốt hơn là sử dụng phương pháp {$ J. Nó hoạt động với các cảnh báo trình biên dịch. Tôi muốn Delphi để có một từ khóa thích hợp như tĩnh để thay thế const/var khi bộ nhớ tĩnh được dự định. Ngay cả chỉ thị trình biên dịch cũng hơi lộn xộn một chút. –

0

Tôi không hiểu câu hỏi hoàn toàn, vì vậy tôi sẽ trả lời tất cả các trường hợp có thể xảy ra:

  1. Nếu bạn không hiểu cách 2 trong số các ví dụ CountWords khác nhau: Đầu tiên tạo và giải phóng cá thể lớp mỗi khi được gọi. Thứ hai chỉ tạo ra cá thể lớp trên cuộc gọi đầu tiên, sau đó sử dụng nó cho đến khi chương trình kết thúc.
  2. Nếu bạn có ý nghĩa như thế nào nếu bạn tạo ra một singleton và thực hiện CountWords trong đó: nó sẽ không khác nhau về chức năng, nhưng bạn sẽ phải viết một lớp hoàn toàn mới cho nó, sau đó khởi tạo nó trên chương trình bắt đầu và sử dụng trễ rồi. Bên cạnh đó có rất nhiều lời chỉ trích về việc sử dụng đơn (xem wiki để biết thêm thông tin), vì vậy tôi sẽ không làm điều đó.
  3. Nếu bạn hỏi về công việc thực tế, hai hàm mẫu này đang thực hiện: chúng rõ ràng mang lại kết quả tương tự, nhưng đầu tiên không được tối ưu hóa để chạy trong môi trường gọi hàm này rất nhiều. Như tôi đã nói trước đây, bạn có thể đạt được kết quả tương tự bằng cách khai báo biến toàn cục, nhưng nếu bạn làm điều đó - bạn sẽ thấy biến toàn cầu của mình ở mọi nơi trong chương trình, trong khi nó chỉ cần ở một vị trí cụ thể và không nơi nào khác.

P.S. Tôi đã thực sự sai về các thông số chức năng const, nó chỉ ra những điều này hoạt động khác nhau trong các phiên bản delphi khác nhau. Tham số Const hoạt động giống như tham số var trong Delphi 6, nhưng trong Delphi XE2 có vẻ như biến cục bộ được tạo ra. Dù bằng cách nào tôi không khuyên bạn nên rối tung với thông số chức năng const.

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