Urutan evaluasi dalam parameter fungsi C ++

90

Jika kita memiliki tiga fungsi (foo, bar, dan baz) yang dikomposisikan seperti ...

foo(bar(), baz())

Apakah ada jaminan oleh standar C ++ bahwa bar akan dievaluasi sebelum baz?

Clark Gaebel
sumber

Jawaban:

102

Tidak, tidak ada jaminan seperti itu. Ini tidak ditentukan menurut standar C ++.

Bjarne Stroustrup juga mengatakannya secara eksplisit dalam "The C ++ Programming Language" edisi ke-3 bagian 6.2.2, dengan beberapa alasan:

Kode yang lebih baik dapat dihasilkan tanpa adanya batasan pada urutan evaluasi ekspresi

Meskipun secara teknis ini mengacu pada bagian awal dari bagian yang sama yang mengatakan bahwa urutan evaluasi bagian ekspresi juga tidak ditentukan, yaitu

int x = f(2) + g(3);   // unspecified whether f() or g() is called first
Eli Bendersky
sumber
Saya dapat menerima jawaban ini dalam 8 menit ... Saya kira saya bertahan sebentar!
Clark Gaebel
4
Ya, tetapi kode yang lebih baik dapat DITULIS (= lebih bersih) jika urutan evaluasi ekspresi STRICT, yang umumnya jauh lebih penting daripada pembuatan kode. Lihat contoh ini: stackoverflow.com/questions/43612592/… Jadi begitulah, Stroustrup.
Bill Kotsias
1
Jika pemesanan penting, Anda bebas melakukan pengurutan sendiri. Melakukan sebaliknya akan selalu menimbulkan biaya untuk sesuatu yang tidak selalu (jarang?) Penting. Saya pikir kebijakan tidak membayar untuk apa yang tidak Anda gunakan adalah satu-satunya hal yang disetujui oleh sebagian besar programmer C ++.
tweej
3
Bukankah seharusnya "perilaku tidak ditentukan" alih-alih "tidak ditentukan"?
GoodDeeds
1
@ChrisDodd downvoting jawaban yang diterima karena menggunakan kata "tidak ditentukan" vs. "tidak ditentukan" terasa seperti tipu muslihat berbahaya bagi saya ... Saya tidak mengatakan ini adalah "perilaku tidak ditentukan", dan sebaliknya "tidak ditentukan" dan "tidak ditentukan" tampaknya sinonim? Bagaimanapun, mengusulkan pengeditan pada jawaban akan menjadi cara yang lebih produktif untuk membahas hal ini
Eli Bendersky
21

Dari [5.2.2] Panggilan fungsi,

Urutan evaluasi argumen tidak ditentukan. Semua efek samping dari evaluasi ekspresi argumen berlaku sebelum fungsi dimasukkan.

Oleh karena itu, tidak ada jaminan yang bar()akan berjalan sebelumnya baz(), hanya itu bar()dan baz()akan dipanggil sebelumnya foo.

Perhatikan juga dari [5] Ekspresi bahwa:

kecuali jika dicatat [misalnya aturan khusus untuk &&dan ||], urutan evaluasi operan dari masing-masing operator dan subekspresi ekspresi individu, dan urutan efek samping yang terjadi, tidak ditentukan.

jadi meskipun Anda bertanya apakah bar()akan dijalankan sebelumnya baz()dalam foo(bar() + baz()), urutannya masih belum ditentukan.

Daniel Trebbien
sumber
4
Contoh "catatan khusus" dari [5.14] Operator logika AND: "Tidak seperti &, &&menjamin evaluasi kiri-ke-kanan: operan kedua tidak dievaluasi jika operan pertama adalah false."
Daniel Trebbien
20

Tidak ada urutan tertentu untuk bar () dan baz () - satu-satunya hal yang dikatakan Standar adalah bahwa keduanya akan dievaluasi sebelum foo () dipanggil. Dari C ++ Standard, bagian 5.2.2 / 8:

Urutan evaluasi argumen tidak ditentukan.


sumber
4
Fakta bahwa mereka dievaluasi sebelum foo () sedikit meyakinkan, setidaknya.
Bill Kotsias
1
@BillKotsias Standar ini juga mengatakan pemanggilan fungsi tidak boleh tumpang tindih (misalnya, implementasi tidak dapat menjalankan baris 1 bar, lalu baris 1 baz, lalu baris 2 bar, dll.), Yang juga bagus. :-)
melpomene
3

Di C ++ 11, teks yang relevan dapat ditemukan di 8.3.6 Argumen default / 9 (Emphasis mine)

Argumen default dievaluasi setiap kali fungsi dipanggil. Urutan evaluasi argumen fungsi tidak ditentukan . Akibatnya, parameter fungsi tidak boleh digunakan dalam argumen default, bahkan jika tidak dievaluasi.

Kata-kata yang sama digunakan oleh standar C ++ 14 juga, dan ditemukan di bawah bagian yang sama .

R Sahu
sumber
0

Seperti yang telah ditunjukkan oleh orang lain, standar ini tidak memberikan panduan apa pun tentang urutan evaluasi untuk skenario khusus ini. Urutan evaluasi ini kemudian diserahkan kepada kompilator, dan kompilator mungkin memiliki jaminan.

Penting untuk diingat bahwa standar C ++ sebenarnya adalah bahasa yang menginstruksikan kompiler untuk membuat kode assembly / mesin. Standar hanyalah salah satu bagian dari persamaan. Jika standarnya ambigu atau secara spesifik ditentukan oleh implementasi, Anda harus beralih ke compiler dan memahami cara menerjemahkan instruksi C ++ ke dalam bahasa mesin yang sebenarnya.

Jadi, jika urutan evaluasi adalah suatu persyaratan, atau setidaknya penting, dan menjadi kompatibel lintas-kompiler bukanlah suatu persyaratan, selidiki bagaimana kompiler Anda pada akhirnya akan menyatukannya, jawaban Anda mungkin terletak di sana. Perhatikan bahwa kompilator dapat mengubah metodologi itu di masa mendatang

Programmer terpelajar
sumber