ลำดับของการประเมินในพารามิเตอร์ฟังก์ชัน C ++


92

ถ้าเรามีฟังก์ชันสามอย่าง (foo, bar และ baz) ที่ประกอบกันเช่นนั้น ...

foo(bar(), baz())

มีการรับประกันใด ๆ ตามมาตรฐาน C ++ ที่แถบจะได้รับการประเมินก่อน baz?

คำตอบ:


103

ไม่ไม่มีการรับประกันดังกล่าว ไม่ได้ระบุตามมาตรฐาน C ++

Bjarne Stroustrup ยังกล่าวอย่างชัดเจนใน "The C ++ Programming Language" 3rd edition section 6.2.2 โดยมีเหตุผลบางประการ:

สามารถสร้างโค้ดที่ดีขึ้นได้โดยไม่มีข้อ จำกัด ในลำดับการประเมินนิพจน์

แม้ว่าในทางเทคนิคแล้วสิ่งนี้หมายถึงส่วนก่อนหน้าของส่วนเดียวกันซึ่งกล่าวว่าลำดับของการประเมินส่วนของนิพจน์นั้นไม่ได้ระบุไว้เช่นกันเช่น

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

ฉันยอมรับคำตอบนี้ได้ใน 8 นาที ... ฉันคิดว่าฉันคงรอสักหน่อย!
Clark Gaebel

5
ใช่ แต่รหัสที่ดีกว่าอาจเป็น WRITTEN (= สะอาดกว่า) หากลำดับการประเมินนิพจน์เป็นแบบ STRICT ซึ่งโดยทั่วไปมีความสำคัญมากกว่าการสร้างโค้ด ดูตัวอย่างนี้: stackoverflow.com/questions/43612592/…มี Stroustrup
Bill Kotsias

1
หากสั่งเรื่องคุณมีอิสระที่จะจัดลำดับด้วยตัวเอง การทำอย่างอื่นมักจะต้องเสียค่าใช้จ่ายสำหรับสิ่งที่ไม่สำคัญเสมอไป (น้อยครั้ง?) ฉันคิดว่านโยบายการไม่จ่ายเงินสำหรับสิ่งที่คุณไม่ได้ใช้เป็นสิ่งเดียวที่โปรแกรมเมอร์ C ++ ส่วนใหญ่เห็นด้วย
tweej

3
ควรเป็น "พฤติกรรมที่ไม่ระบุ" แทนที่จะเป็น "ไม่ระบุ" หรือไม่?
GoodDeeds

1
@ChrisDodd ลงคะแนนคำตอบที่ได้รับการยอมรับเนื่องจากการใช้คำว่า "ไม่ได้กำหนด" กับ "ไม่ระบุ" ให้ความรู้สึกเหมือนเป็นการอวดรู้ที่เป็นอันตรายสำหรับฉัน ... ฉันไม่ได้บอกว่านี่เป็น "พฤติกรรมที่ไม่ได้กำหนด" และดูเหมือนว่า "ไม่ได้กำหนด" และ "ไม่ระบุ" ตรงกัน? ไม่ว่าในกรณีใดการเสนอการแก้ไขคำตอบจะเป็นวิธีที่มีประสิทธิผลมากขึ้นในการพูดคุยเรื่องนี้
Eli Bendersky

21

จาก [5.2.2] การเรียกใช้ฟังก์ชัน

ลำดับของการประเมินข้อโต้แย้งไม่ได้ระบุไว้ ผลข้างเคียงทั้งหมดของการประเมินนิพจน์อาร์กิวเมนต์จะมีผลก่อนป้อนฟังก์ชัน

ดังนั้นจึงมีการรับประกันว่าไม่มีbar()จะทำงานก่อนbaz()เท่านั้นที่bar()และจะถูกเรียกว่าก่อนที่จะbaz()foo

นอกจากนี้โปรดทราบจาก [5] นิพจน์ที่:

ยกเว้นในกรณีที่ระบุไว้ [เช่นกฎพิเศษสำหรับ&&และ||] ลำดับของการประเมินตัวถูกดำเนินการของแต่ละตัวดำเนินการและนิพจน์ย่อยของนิพจน์แต่ละรายการและลำดับที่เกิดผลข้างเคียงไม่ได้ระบุไว้

ดังนั้นแม้ว่าคุณจะถูกถามว่าbar()จะเรียกใช้ก่อนbaz()ในfoo(bar() + baz())การสั่งซื้อยังคงไม่ได้ระบุ


4
ตัวอย่างของการ "หมายเหตุพิเศษ" จาก [5.14] ตรรกะและผู้ประกอบการ "ซึ่งแตกต่าง&, &&การค้ำประกันจากซ้ายไปขวาประเมินผลตัวถูกดำเนินการที่สองคือการไม่ได้รับการประเมินถ้าตัวถูกดำเนินการแรกคือfalse."
Daniel Trebbien

20

ไม่มีลำดับที่ระบุสำหรับ bar () และ baz () - สิ่งเดียวที่ Standard กล่าวคือทั้งคู่จะได้รับการประเมินก่อนที่จะเรียก foo () จากมาตรฐาน C ++ ส่วน 5.2.2 / 8:

ลำดับของการประเมินข้อโต้แย้งไม่ได้ระบุไว้


4
ความจริงที่ว่าพวกเขาได้รับการประเมินก่อน foo () อย่างน้อยก็ทำให้มั่นใจได้
Bill Kotsias

1
@BillKotsias มาตรฐานยังบอกว่าการเรียกใช้ฟังก์ชันไม่สามารถทับซ้อนกันได้ (เช่นการใช้งานไม่สามารถรันบรรทัดที่ 1 จากbarนั้นบรรทัดที่ 1 จากbazนั้นบรรทัดที่ 2 ของbarฯลฯ ) ซึ่งก็ดีเช่นกัน :-)
melpomene

12

C ++ 17 ระบุลำดับการประเมินสำหรับตัวดำเนินการที่ไม่ได้ระบุจนถึง C ++ 17 ดูคำถามอะไรคือคำสั่งค้ำประกันการประเมินที่แนะนำโดย C ++ 17? แต่สังเกตการแสดงออกของคุณ

foo(bar(), baz())

ยังไม่ได้ระบุลำดับการประเมิน


3

ใน C ++ 11 ข้อความที่เกี่ยวข้องสามารถพบได้ใน8.3.6 อาร์กิวเมนต์เริ่มต้น / 9 (เน้นของฉัน)

อาร์กิวเมนต์ดีฟอลต์จะถูกประเมินทุกครั้งที่เรียกใช้ฟังก์ชัน ลำดับของการประเมินผลของการขัดแย้งฟังก์ชั่นที่ไม่ได้ระบุ ดังนั้นจึงห้ามใช้พารามิเตอร์ของฟังก์ชันในอาร์กิวเมนต์เริ่มต้นแม้ว่าจะไม่ได้รับการประเมินก็ตาม

ใช้คำฟุ่มเฟือยเดียวกันถูกใช้โดย C ++ 14 มาตรฐานเช่นกันและพบว่าภายใต้หัวข้อเดียวกัน


0

ตามที่คนอื่น ๆ ได้ชี้ให้เห็นแล้วมาตรฐานไม่ได้ให้คำแนะนำใด ๆ เกี่ยวกับลำดับการประเมินสำหรับสถานการณ์เฉพาะนี้ จากนั้นลำดับของการประเมินผลจะถูกปล่อยให้คอมไพเลอร์และคอมไพเลอร์อาจมีการรับประกัน

สิ่งสำคัญคือต้องจำไว้ว่ามาตรฐาน C ++ เป็นภาษาที่ใช้สั่งคอมไพเลอร์ในการสร้างรหัสแอสเซมบลี / เครื่อง มาตรฐานเป็นเพียงส่วนหนึ่งของสมการ ในกรณีที่มาตรฐานไม่ชัดเจนหรือมีการกำหนดการนำไปใช้โดยเฉพาะคุณควรหันไปใช้คอมไพเลอร์และทำความเข้าใจว่าจะแปลคำสั่ง C ++ เป็นภาษาเครื่องจริงอย่างไร

ดังนั้นหากลำดับของการประเมินผลเป็นข้อกำหนดหรืออย่างน้อยก็สำคัญและการทำงานร่วมกันระหว่างคอมไพเลอร์ไม่ได้เป็นข้อกำหนดให้ตรวจสอบว่าคอมไพเลอร์ของคุณจะรวมสิ่งนี้เข้าด้วยกันในท้ายที่สุดคำตอบของคุณอาจอยู่ที่นั่นได้อย่างไร โปรดทราบว่าคอมไพลเลอร์สามารถเปลี่ยนวิธีการได้ในอนาคต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.