Baru-baru ini dalam sebuah wawancara ada pertanyaan tipe objektif berikut.
int a = 0;
cout << a++ << a;
Jawaban:
Sebuah. 10
b. 01
c. perilaku tidak terdefinisi
Saya menjawab pilihan b, yaitu output akan menjadi "01".
Tapi yang mengejutkan saya kemudian saya diberitahu oleh pewawancara bahwa jawaban yang benar adalah opsi c: tidak ditentukan.
Sekarang, saya tahu konsep poin urutan di C ++. Perilaku tidak ditentukan untuk pernyataan berikut:
int i = 0;
i += i++ + i++;
tetapi sesuai pemahaman saya untuk pernyataan itu cout << a++ << a
, ostream.operator<<()
itu akan dipanggil dua kali, pertama dengan ostream.operator<<(a++)
dan kemudian ostream.operator<<(a)
.
Saya juga memeriksa hasilnya pada kompiler VS2010 dan hasilnya juga '01'.
10
, itu akan menjadi salah satu01
atau00
. (c++
Akan selalu mengevaluasi nilaic
memiliki sebelum yang bertambah). Dan bahkan jika itu tidak terdefinisi, itu masih akan sangat membingungkan.Jawaban:
Anda bisa memikirkan:
Sebagai:
C ++ menjamin bahwa semua efek samping dari evaluasi sebelumnya akan dilakukan pada titik-titik urutan . Tidak ada titik urutan di antara evaluasi argumen fungsi yang berarti bahwa argumen
a
dapat dievaluasi sebelumstd::operator<<(std::cout, a++)
atau sesudah argumen . Jadi hasil di atas tidak terdefinisi.Pembaruan C ++ 17
Di C ++ 17 aturan telah diperbarui. Khususnya:
Yang berarti membutuhkan kode untuk menghasilkan hasil
b
, yang mana keluaran01
.Lihat Urutan Evaluasi Ekspresi Pemurnian P0145R3 untuk C ++ Idiomatik untuk lebih jelasnya.
sumber
c
memiliki tipeint
,operator<<
inilah fungsi anggota.operator<<
fungsi anggota atau fungsi berdiri bebas tidak mempengaruhi titik urutan.So the result of the above is undefined.
Penjelasan Anda hanya bagus untuk yang tidak ditentukan , bukan untuk yang tidak ditentukan . JamesKanze menjelaskan bagaimana semakin memberatkan terdefinisi dalam jawabannya meskipun .Secara teknis, secara keseluruhan ini adalah Perilaku yang Tidak Terdefinisi .
Namun, ada dua aspek penting jawabannya.
Pernyataan kode:
dievaluasi sebagai:
Standar tidak menentukan urutan evaluasi argumen ke suatu fungsi.
Jadi salah satu:
std::operator<<(std::cout, a++)
dievaluasi terlebih dahulu ataua
dievaluasi terlebih dahulu atauPesanan ini Tidak Ditentukan [Ref 1] sesuai standar.
[Ref 1] C ++ 03 5.2.2 Panggilan fungsi
Para 8
Selanjutnya, tidak ada titik urutan antara evaluasi argumen ke fungsi tetapi titik urutan hanya ada setelah evaluasi semua argumen [Ref 2] .
[Ref 2] C ++ 03 1.9 Eksekusi program [intro.execution]:
Para 17:
Perhatikan bahwa, di sini nilai
c
sedang diakses lebih dari sekali tanpa titik urutan yang mengganggu, standarnya mengatakan:[Ref 3] C ++ 03 5 Ekspresi [expr]:
Para 4:
Kode memodifikasi
c
lebih dari sekali tanpa mengintervensi titik urutan dan tidak sedang diakses untuk menentukan nilai objek yang disimpan. Ini jelas merupakan pelanggaran terhadap klausul di atas dan karenanya hasil seperti yang diamanatkan oleh standar adalah Perilaku Tidak Terdefinisi [Ref 3] .sumber
Poin urutan hanya menentukan urutan parsial . Dalam kasus Anda, Anda memiliki (setelah resolusi kelebihan beban selesai):
Ada titik urutan antara
a++
panggilan pertama dan kestd::ostream::operator<<
, dan ada titik urutan antaraa
panggilan kedua dan kedua kestd::ostream::operator<<
, tetapi tidak ada titik urutan antaraa++
dana
; satu-satunya batasan urutan adalah yanga++
sepenuhnya dievaluasi (termasuk efek samping) sebelum panggilan pertama keoperator<<
, dan yang keduaa
dievaluasi sepenuhnya sebelum panggilan kedua keoperator<<
. (Ada juga batasan urutan kausual: panggilan kedua keoperator<<
tidak dapat mendahului yang pertama, karena ini membutuhkan hasil dari yang pertama sebagai argumen.) §5 / 4 (C ++ 03) menyatakan:Salah satu urutan ekspresi Anda yang diperbolehkan adalah
a++
,,a
panggilan pertama keoperator<<
, panggilan kedua keoperator<<
; ini mengubah nilai yang disimpan daria
(a++
), dan mengaksesnya selain untuk menentukan nilai baru (yang keduaa
), perilakunya tidak ditentukan.sumber
c
adalah tipe pengguna dengan pengguna yang ditentukan++
,int
hasilnya tidak akan ditentukan, tetapi tidak akan ada perilaku yang tidak ditentukan.c
dalamfoo(foo(bar(c)), c)
? Ada titik urutan ketika fungsi dipanggil, dan kapan mereka kembali, tetapi tidak ada pemanggilan fungsi yang diperlukan di antara evaluasi keduanyac
.c
UDT, operator yang kelebihan beban akan menjadi pemanggilan fungsi, dan akan memperkenalkan titik urutan, sehingga perilaku tidak akan terdefinisi. Tapi masih belum ditentukan apakah sub-ekspresic
dievaluasi sebelum atau sesudahc++
, jadi apakah Anda mendapatkan versi tambahan atau tidak tidak akan ditentukan (dan secara teori, tidak harus sama setiap saat).c
danc++
, jadi keduanya dapat muncul dalam urutan apa pun. Adapun titik koma ... Mereka hanya menyebabkan titik urutan sejauh ekspresi penuh. Titik urutan penting lainnya adalah pemanggilan fungsi:f(c++)
akan melihat bertambahnyac
masukf
, dan operator koma&&
,||
dan?:
juga menyebabkan titik urutan.Jawaban yang benar adalah mempertanyakan pertanyaan itu. Pernyataan tersebut tidak dapat diterima karena pembaca tidak dapat melihat jawaban yang jelas. Cara lain untuk melihatnya adalah bahwa kami telah memperkenalkan efek samping (c ++) yang membuat pernyataan tersebut jauh lebih sulit untuk ditafsirkan. Kode yang ringkas itu bagus, asalkan artinya jelas.
sumber