Chính xác thì quy tắc "as-if" là gì?


89

Như tiêu đề đã nói,

Chính xác thì quy tắc "as-if" là gì?

Một câu trả lời điển hình mà người ta sẽ nhận được là:

Quy tắc cho phép bất kỳ và tất cả các phép biến đổi mã không thay đổi hành vi có thể quan sát được của chương trình

Đôi khi, chúng tôi tiếp tục nhận được các hành vi từ một số triển khai nhất định được quy cho quy tắc này. Nhiều khi sai. Vì vậy, những gì chính xác là quy tắc này. Tiêu chuẩn không đề cập rõ ràng quy tắc này như một phần hoặc đoạn văn, vậy chính xác thì điều gì nằm trong mục đích của quy tắc này? Đối với tôi, nó có vẻ như là một vùng xám không được xác định chi tiết theo tiêu chuẩn. Ai đó có thể giải thích chi tiết trích dẫn các tài liệu tham khảo từ tiêu chuẩn không?

Lưu ý: Gắn thẻ này là C và C ++, vì nó có liên quan đến cả hai ngôn ngữ.


2
Nó đề cập đến máy trừu tượng.
Alexey Frunze

" Gắn thẻ này là C và C ++, vì nó có liên quan đến cả hai ngôn ngữ " Nó có liên quan trong bất kỳ ngôn ngữ nào.
tò mò

@AlexeyFrunze " Nó đề cập đến máy trừu tượng " Nó đề cập đến trạng thái của "máy trừu tượng" là một công cụ chứ không phải kết thúc và không liên quan về mặt tuân thủ, vì nó "trừu tượng" là một công cụ đặc tả không có thật.
tò mò

Câu trả lời:


98

"Là gì như-nếu " quy tắc?

Quy tắc " as-if " về cơ bản xác định những chuyển đổi nào mà một triển khai được phép thực hiện trên một chương trình C ++ hợp pháp. Tóm lại, tất cả các phép biến đổi không ảnh hưởng đến " hành vi có thể quan sát được " của chương trình (xem định nghĩa chính xác bên dưới) đều được phép.

Mục đích là cho phép các triển khai tự do thực hiện tối ưu hóa miễn là hành vi của chương trình vẫn tuân thủ ngữ nghĩa được Chỉ định bởi Tiêu chuẩn C ++ về mặt máy trừu tượng.


Tiêu chuẩn đưa ra quy tắc này ở đâu?

Tiêu chuẩn C ++ 11 giới thiệu quy tắc " as-if " trong Đoạn 1.9 / 1:

Các mô tả ngữ nghĩa trong tiêu chuẩn này xác định một máy trừu tượng không xác định được tham số hóa. Tiêu chuẩn này không yêu cầu về cấu trúc của việc triển khai phù hợp. Đặc biệt, họ không cần sao chép hoặc mô phỏng cấu trúc của máy trừu tượng. Thay vào đó, các triển khai tuân thủ được yêu cầu để mô phỏng (chỉ) hành vi có thể quan sát được của máy trừu tượng như được giải thích bên dưới.

Ngoài ra, một chú thích giải thích cho biết thêm:

Quy định này đôi khi được gọi là quy tắc “nếu có” , bởi vì việc thực hiện có thể tự do bỏ qua bất kỳ yêu cầu nào của tiêu chuẩn này miễn là kết quả là như thể yêu cầu đã được tuân theo, chừng nào có thể xác định được từ hành vi quan sát được. của chương trình. Ví dụ, một triển khai thực tế không cần đánh giá một phần của biểu thức nếu nó có thể suy ra rằng giá trị của nó không được sử dụng và không có tác dụng phụ nào ảnh hưởng đến hành vi quan sát được của chương trình được tạo ra.


Quy tắc bắt buộc chính xác là gì?

Đoạn 1.9 / 5 chỉ rõ thêm:

Một triển khai tuân thủ thực hiện một chương trình được định dạng tốt sẽ tạo ra cùng một hành vi có thể quan sát được như một trong những thực thi có thể có của phiên bản tương ứng của máy trừu tượng với cùng một chương trình và cùng một đầu vào . Tuy nhiên, nếu bất kỳ quá trình thực hiện nào như vậy chứa một thao tác không xác định, thì tiêu chuẩn này không đặt ra yêu cầu đối với việc triển khai thực hiện chương trình đó với đầu vào đó (thậm chí không liên quan đến các thao tác trước thao tác không xác định đầu tiên).

Cần nhấn mạnh rằng ràng buộc này chỉ áp dụng khi "thực thi một chương trình đã được định dạng tốt" và các kết quả có thể có của việc thực thi một chương trình có chứa hành vi không xác định là không bị hạn chế. Điều này cũng được trình bày rõ ràng trong Đoạn 1.9 / 4:

Một số hoạt động khác được mô tả trong tiêu chuẩn này là không xác định (ví dụ, tác động của việc cố gắng sửa đổi đối tượng const). [Lưu ý: Tiêu chuẩn này không áp đặt yêu cầu đối với hoạt động của các chương trình có chứa hành vi không xác định . —Gửi ghi chú]

Cuối cùng, liên quan đến định nghĩa " hành vi có thể quan sát được ", Đoạn 1.9 / 8 trình bày như sau:

Các yêu cầu ít nhất đối với việc triển khai tuân thủ là:

- Quyền truy cập vào các đối tượng dễ bay hơi được đánh giá nghiêm ngặt theo các quy tắc của máy trừu tượng.

- Khi kết thúc chương trình, tất cả dữ liệu được ghi vào tệp phải giống với một trong những kết quả có thể có mà việc thực thi chương trình theo ngữ nghĩa trừu tượng sẽ tạo ra.

- Động lực đầu vào và đầu ra của các thiết bị tương tác phải diễn ra theo cách mà đầu ra nhắc nhở thực sự được phân phối trước khi chương trình đợi đầu vào. Những gì cấu thành một thiết bị tương tác được xác định bởi việc triển khai.

Chúng được gọi chung là hành vi quan sát được của chương trình . [ Lưu ý : Tương ứng nghiêm ngặt hơn giữa ngữ nghĩa trừu tượng và thực tế có thể được xác định bởi mỗi triển khai. - ghi chú cuối ]


Có những trường hợp nào mà quy tắc này không được áp dụng không?

Theo hiểu biết tốt nhất của tôi, ngoại lệ duy nhất đối với quy tắc " as-if " là sao chép / di chuyển elision, được phép mặc dù hàm tạo bản sao, hàm tạo di chuyển hoặc hàm hủy của một lớp có tác dụng phụ. Các điều kiện chính xác cho việc này được quy định trong Đoạn 12.8 / 31:

Khi đáp ứng một số tiêu chí nhất định, việc triển khai được phép bỏ qua việc sao chép / di chuyển cấu trúc của một đối tượng lớp, ngay cả khi hàm tạo được chọn cho hoạt động sao chép / di chuyển và / hoặc trình hủy cho đối tượng có tác dụng phụ . [...]


2
Tôi đã thấy trích dẫn này. Điều không rõ ràng là định nghĩa của hành vi có thể quan sát được. Chính xác điều gì được coi là một hành vi có thể quan sát được? Copy elision là một ngoại lệ đối với quy tắc as-if được khá nhiều người biết đến và thực sự không phải là một phần trong câu hỏi của tôi.
Alok Save

2
@AlokSave: Trong tiêu chuẩn C, chúng ta thấy "Truy cập một đối tượng dễ bay hơi, sửa đổi một đối tượng, sửa đổi tệp hoặc gọi một hàm thực hiện bất kỳ hoạt động nào trong số đó đều là tác dụng phụ". Có lẽ có một cái gì đó tương đương trong (các) tiêu chuẩn C ++. Một cách không chính thức, tôi đoán là "bất cứ thứ gì thay đổi tương tác của nó với thế giới bên ngoài".
Oliver Charlesworth

1
Bất kỳ hành vi nào làm thay đổi trạng thái của máy trừu tượng (vì vậy, một cái gì đó thay đổi một biến được truyền vào hoặc biến toàn cục, hoặc đọc và ghi vào các thiết bị I / O).
Mats Petersson

1
Điều này có nghĩa là xóa một vòng lặp vô hạn không được phép, miễn là không có gì có thể quan sát được xảy ra sau đó?
harold

5
Một điểm cần đặc biệt lưu ý là nó chỉ áp dụng cho các chương trình hợp pháp . Bất kỳ điều gì gọi hành vi không xác định rõ ràng là nằm ngoài phạm vi bảo hiểm.
vonbrand

15

Trong C11 quy tắc không bao giờ được gọi bằng tên đó. Tuy nhiên, C, cũng giống như C ++, định nghĩa hành vi dưới dạng máy trừu tượng. Quy tắc as-if trong C11 5.1.2.3p4 và p6 :

  1. Trong máy trừu tượng, tất cả các biểu thức được đánh giá như được chỉ định bởi ngữ nghĩa. Việc triển khai thực tế không cần phải đánh giá một phần của biểu thức nếu nó có thể suy ra rằng giá trị của nó không được sử dụng và không có tác dụng phụ cần thiết nào được tạo ra (bao gồm bất kỳ tác dụng phụ nào gây ra bởi việc gọi một hàm hoặc truy cập một đối tượng dễ bay hơi).

  2. [...]

  3. Các yêu cầu ít nhất đối với việc triển khai tuân thủ là:

    • Các truy cập vào volatilecác đối tượng được đánh giá nghiêm ngặt theo các quy tắc của máy trừu tượng.
    • Khi kết thúc chương trình, tất cả dữ liệu được ghi vào tệp sẽ giống với kết quả mà việc thực thi chương trình theo ngữ nghĩa trừu tượng sẽ tạo ra.
    • Động lực đầu vào và đầu ra của các thiết bị tương tác phải diễn ra như quy định trong 7.21.3 . Mục đích của các yêu cầu này là đầu ra không có bộ đệm hoặc có bộ đệm dòng xuất hiện càng sớm càng tốt, để đảm bảo rằng các thông báo nhắc thực sự xuất hiện trước khi một chương trình đang đợi đầu vào.

     

    Đây là hành vi quan sát được của chương trình.


-1

Trong C, C ++, Ada, Java, SML ... trong bất kỳ ngôn ngữ lập trình nào được chỉ định rõ ràng bằng cách mô tả (thường là nhiều hành vi có thể có, không xác định) của một chương trình (tiếp xúc với một loạt các tương tác trên các cổng I / O) , không có quy tắc as-if riêng biệt .

Một ví dụ về quy tắc khác biệt là quy tắc nói rằng phép chia cho 0 tạo ra một ngoại lệ (Ada, Caml) hoặc một tham chiếu rỗng tạo ra một ngoại lệ (Java). Bạn có thể thay đổi quy tắc để chỉ định một thứ gì đó khác và cuối cùng bạn sẽ sử dụng một ngôn ngữ khác (mà một số người muốn gọi là "phương ngữ" (*). Một quy tắc riêng biệt có để chỉ định một số cách sử dụng riêng biệt của một ngôn ngữ lập trình như một ngôn ngữ lập trình riêng biệt quy tắc ngữ pháp bao hàm một số cấu trúc cú pháp.

(*) Phương ngữ theo một số nhà ngôn ngữ học là ngôn ngữ có “quân”. trong bối cảnh đó, điều đó có thể có nghĩa là một ngôn ngữ lập trình không có ủy ban và một ngành cụ thể gồm các trình biên dịch trình biên dịch.

Quy tắc as-if không phải là một quy tắc riêng biệt ; nó không bao gồm bất kỳ chương trình nào cụ thể và thậm chí không phải là một quy tắc có thể được thảo luận, loại bỏ hoặc thay đổi theo bất kỳ cách nào : cái gọi là "quy tắc" chỉ đơn giản nhắc lại rằng ngữ nghĩa của chương trình đã được xác định và chỉ có thể được di động (phổ biến) được định nghĩa, xét về các tương tác có thể nhìn thấy được của quá trình thực thi chương trình với thế giới "bên ngoài".

Thế giới bên ngoài có thể là giao diện I / O (stdio), GUI, thậm chí là trình thông dịch tương tác xuất ra giá trị kết quả của một ngôn ngữ ứng dụng thuần túy. Trong C và C ++ bao gồm các quyền truy cập (được chỉ định một cách mơ hồ) đến các đối tượng dễ bay hơi, đó là một cách nói khác rằng một số đối tượng tại điểm đã cho phải được biểu diễn trong bộ nhớ theo đúng ABI (Application Binary Interface) mà không bao giờ đề cập đến ABI một cách rõ ràng.

Định nghĩa về một dấu vết của việc thực thi , còn được gọi là hành vi có thể nhìn thấy hoặc có thể quan sát được xác định ý nghĩa của "quy tắc như thể". Quy tắc as-if cố gắng giải thích điều đó, nhưng bằng cách làm như vậy, nó khiến mọi người bối rối hơn là làm rõ mọi thứ vì nó mang lại biểu hiện là một quy tắc ngữ nghĩa bổ sung mang lại nhiều thời gian hơn cho việc triển khai.

Tóm lược:

  • Cái gọi là "quy tắc như thể" không nới lỏng bất kỳ ràng buộc nào đối với việc triển khai.
  • Bạn không thể xóa quy tắc as-if trong bất kỳ ngôn ngữ lập trình nào được chỉ định về hành vi hiển thị (dấu vết thực thi được tạo ra để tương tác với thế giới bên ngoài) để có được một phương ngữ riêng biệt.
  • Bạn không thể thêm quy tắc as-if vào bất kỳ ngôn ngữ lập trình nào không được chỉ định về hành vi hiển thị.

Nếu mọi người tin rằng tôi sai và có một "quy tắc như thể" riêng biệt, tại sao họ không thử mô tả một biến thể của C ++ (một phương ngữ) với "quy tắc" đó? Đặc tả C ++ thậm chí có nghĩa là gì nếu nó? Sẽ hoàn toàn không thể biết liệu một trình biên dịch có phù hợp hay không. Hoặc thậm chí xác định sự phù hợp.
tò mò
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.