Thứ tự đánh giá trong tham số hàm C ++


90

Nếu chúng ta có ba hàm (foo, bar và baz) được cấu tạo như vậy ...

foo(bar(), baz())

Có đảm bảo nào theo tiêu chuẩn C ++ rằng thanh sẽ được đánh giá trước baz không?

Câu trả lời:


102

Không, không có gì đảm bảo. Nó không xác định theo tiêu chuẩn C ++.

Bjarne Stroustrup cũng nói rõ điều đó trong phần 6.2.2 của "Ngôn ngữ lập trình C ++" phiên bản thứ 3, với một số lý do:

Mã tốt hơn có thể được tạo ra mà không có hạn chế về thứ tự đánh giá biểu thức

Mặc dù về mặt kỹ thuật, điều này đề cập đến một phần trước đó của cùng một phần nói rằng thứ tự đánh giá các phần của một biểu thức cũng không được xác định, tức là

int x = f(2) + g(3);   // unspecified whether f() or g() is called first

Tôi có thể chấp nhận câu trả lời này sau 8 phút ... Tôi đoán là tôi đang cố gắng một chút!
Clark Gaebel

4
Có, nhưng mã tốt hơn có thể là WRITTEN (= clean) nếu thứ tự đánh giá biểu thức là NGHIÊM TÚC, điều này thường quan trọng hơn rất nhiều so với việc tạo mã. Hãy xem ví dụ này: stackoverflow.com/questions/43612592/… Vì vậy, Stroustrup.
Bill Kotsias

1
Nếu vấn đề đặt hàng, bạn có thể tự do thực hiện trình tự. Làm khác đi sẽ luôn luôn phải trả một chi phí cho một cái gì đó không phải lúc nào (hiếm khi?) Cũng quan trọng. Tôi nghĩ chính sách không trả tiền cho những gì bạn không sử dụng là điều duy nhất mà hầu hết các lập trình viên C ++ đồng ý.
tweej

3
Nó không phải là "hành vi không xác định" thay vì "không xác định"?
GoodDeeds

1
@ChrisDodd từ chối một câu trả lời được chấp nhận do sử dụng từ "không xác định" so với "không xác định" khiến tôi cảm thấy giống như một câu chuyện ác ý ... Tôi không nói đây là "hành vi không xác định", và nếu không thì có vẻ "không xác định" và "không xác định" đồng nghĩa? Trong mọi trường hợp, đề xuất một sửa để câu trả lời sẽ là một cách hiệu quả hơn để thảo luận này
Eli Bendersky

20

Không có thứ tự cụ thể nào cho bar () và baz () - điều duy nhất mà Tiêu chuẩn nói là cả hai đều sẽ được đánh giá trước khi foo () được gọi. Từ Tiêu chuẩn C ++, phần 5.2.2 / 8:

Thứ tự đánh giá các lập luận là không xác định.


4
Thực tế là chúng được đánh giá trước foo () là một chút yên tâm, ít nhất.
Bill Kotsias

1
@BillKotsias Tiêu chuẩn cũng nói rằng các lệnh gọi hàm không được trùng lặp (tức là một triển khai không thể chạy dòng 1 bar, rồi dòng 1 baz, rồi dòng 2 bar, v.v.), điều này cũng rất hay. :-)
melpomene

20

Từ [5.2.2] Cuộc gọi hàm,

Thứ tự đánh giá các lập luận là không xác định. Tất cả các hiệu ứng phụ của đánh giá biểu thức đối số có hiệu lực trước khi hàm được nhập.

Do đó, không có gì đảm bảo rằng nó bar()sẽ chạy trước đó baz(), chỉ có điều đó bar()baz()sẽ được gọi trước đó foo.

Cũng lưu ý từ [5] Biểu thức rằng:

ngoại trừ khi được lưu ý [ví dụ: các quy tắc đặc biệt cho &&||], thứ tự đánh giá toán hạng của các toán tử riêng lẻ và biểu thức con của các biểu thức riêng lẻ, và thứ tự diễn ra các tác dụng phụ, là không xác định.

vì vậy ngay cả khi bạn đang đặt câu hỏi liệu bar()sẽ chạy trước khi baz()vào foo(bar() + baz()), thứ tự là vẫn chưa được xác định.


4
Ví dụ về "ghi chú đặc biệt" từ [5.14] Toán tử logic AND: "Không giống như &, &&đảm bảo đánh giá từ trái sang phải: toán hạng thứ hai không được đánh giá nếu toán hạng đầu tiên là false."
Daniel Trebbien


2

Trong C ++ 11, văn bản liên quan có thể được tìm thấy trong 8.3.6 Đối số mặc định / 9 (Mỏ nhấn mạnh)

Các đối số mặc định được đánh giá mỗi khi hàm được gọi. Thứ tự đánh giá của các đối số hàm là không xác định . Do đó, các tham số của một hàm sẽ không được sử dụng trong một đối số mặc định, ngay cả khi chúng không được đánh giá.

Xung quanh tương tự cũng được sử dụng bởi tiêu chuẩn C ++ 14 và được tìm thấy trong cùng một phần .


0

Như những người khác đã chỉ ra, tiêu chuẩn không đưa ra bất kỳ hướng dẫn nào về trình tự đánh giá cho tình huống cụ thể này. Thứ tự đánh giá này sau đó được để lại cho trình biên dịch và trình biên dịch có thể có một đảm bảo.

Điều quan trọng cần nhớ là tiêu chuẩn C ++ thực sự là một ngôn ngữ để hướng dẫn trình biên dịch về việc xây dựng assembly / mã máy. Tiêu chuẩn chỉ là một phần của phương trình. Trường hợp tiêu chuẩn không rõ ràng hoặc được xác định cụ thể việc triển khai, bạn nên chuyển sang trình biên dịch và hiểu cách nó dịch các lệnh C ++ thành ngôn ngữ máy thực sự.

Vì vậy, nếu thứ tự đánh giá là một yêu cầu, hoặc ít nhất là quan trọng và việc tương thích với nhiều trình biên dịch không phải là một yêu cầu, hãy điều tra xem cuối cùng trình biên dịch của bạn sẽ kết hợp điều này như thế nào, câu trả lời của bạn cuối cùng có thể nằm ở đó. Lưu ý rằng trình biên dịch có thể thay đổi phương pháp của nó trong tương lai

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.