Keduanya (a)
dan (b)
menghasilkan perilaku yang tidak terdefinisi. Itu selalu merupakan perilaku yang tidak terdefinisi untuk memanggil fungsi anggota melalui penunjuk null. Jika fungsinya statis, secara teknis juga tidak ditentukan, tetapi ada beberapa perselisihan.
Hal pertama yang harus dipahami adalah mengapa perilaku tidak terdefinisi dengan merujuk pointer nol. Di C ++ 03, sebenarnya ada sedikit ambiguitas di sini.
Meskipun "dereferensi penunjuk nol menghasilkan perilaku yang tidak ditentukan" disebutkan dalam catatan di §1.9 / 4 dan §8.3.2 / 4, hal itu tidak pernah dinyatakan secara eksplisit. (Catatan tidak normatif.)
Namun, seseorang dapat mencoba menyimpulkannya dari §3.10 / 2:
Nilai l mengacu pada objek atau fungsi.
Saat melakukan dereferensi, hasilnya adalah nilai l. Pointer nol tidak merujuk ke objek, oleh karena itu ketika kita menggunakan lvalue kita memiliki perilaku yang tidak terdefinisi. Masalahnya adalah kalimat sebelumnya tidak pernah disebutkan, jadi apa artinya "menggunakan" lvalue? Bahkan hanya menghasilkannya sama sekali, atau menggunakannya dalam arti yang lebih formal yaitu melakukan konversi lvalue-to-rvalue?
Terlepas dari itu, pasti tidak dapat dikonversi ke nilai r (§4.1 / 1):
Jika objek yang dirujuk nilai l bukan objek tipe T dan bukan objek dari tipe yang diturunkan dari T, atau jika objek tidak diinisialisasi, program yang memerlukan konversi ini memiliki perilaku yang tidak ditentukan.
Ini jelas perilaku yang tidak terdefinisi.
Ambiguitas berasal dari apakah perilaku tidak terdefinisi menjadi deference atau tidak, tetapi tidak menggunakan nilai dari penunjuk yang tidak valid (yaitu, dapatkan nilai l tetapi tidak mengubahnya menjadi nilai r). Jika tidak, maka int *i = 0; *i; &(*i);
sudah didefinisikan dengan baik. Ini adalah masalah aktif .
Jadi kita memiliki tampilan "dereferensi null pointer, dapatkan perilaku tidak terdefinisi" dan tampilan "lemah" menggunakan pointer null yang terdefinisi, dapatkan perilaku tidak terdefinisi ".
Sekarang kita pertimbangkan pertanyaannya.
Ya, (a)
menghasilkan perilaku tidak terdefinisi. Faktanya, jika this
null maka terlepas dari konten fungsinya , hasilnya tidak ditentukan.
Ini mengikuti dari §5.2.5 / 3:
Jika E1
memiliki tipe "penunjuk ke kelas X", ekspresi E1->E2
tersebut akan diubah ke bentuk yang setara(*(E1)).E2;
*(E1)
akan menghasilkan perilaku tidak terdefinisi dengan interpretasi yang ketat, dan .E2
mengubahnya menjadi nilai r, menjadikannya perilaku tak terdefinisi untuk interpretasi yang lemah.
Ini juga mengikuti bahwa itu perilaku yang tidak ditentukan langsung dari (§9.3.1 / 1):
Jika fungsi anggota nonstatic dari kelas X dipanggil untuk objek yang bukan tipe X, atau tipe turunan dari X, perilakunya tidak ditentukan.
Dengan fungsi statis, interpretasi yang ketat versus lemah membuat perbedaan. Sebenarnya, ini tidak ditentukan:
Anggota statis dapat dirujuk menggunakan sintaks akses anggota kelas, dalam hal ini ekspresi objek dievaluasi.
Artinya, itu dievaluasi seolah-olah itu non-statis dan kami sekali lagi dereferensi pointer nol dengan (*(E1)).E2
.
Namun, karena E1
tidak digunakan dalam panggilan fungsi-anggota statis, jika kita menggunakan interpretasi yang lemah, panggilan tersebut didefinisikan dengan baik. *(E1)
menghasilkan nilai l, fungsi statis diselesaikan, *(E1)
dibuang, dan fungsi dipanggil. Tidak ada konversi lvalue-to-rvalue, jadi tidak ada perilaku yang tidak ditentukan.
Di C ++ 0x, pada n3126, ambiguitas tetap ada. Untuk saat ini, berhati-hatilah: gunakan interpretasi yang ketat.