- Ada banyak contoh fungsi yang saya tahu tidak akan pernah dilempar, tetapi kompiler tidak dapat menentukannya sendiri. Haruskah saya menambahkan noexcept ke deklarasi fungsi dalam semua kasus seperti itu?
noexcept
rumit, karena merupakan bagian dari antarmuka fungsi. Terutama, jika Anda menulis perpustakaan, kode klien Anda dapat bergantung pada noexcept
properti. Mungkin sulit untuk mengubahnya nanti, karena Anda mungkin merusak kode yang ada. Itu mungkin tidak terlalu menjadi perhatian ketika Anda menerapkan kode yang hanya digunakan oleh aplikasi Anda.
Jika Anda memiliki fungsi yang tidak dapat dilempar, tanyakan pada diri Anda apakah itu akan tetap noexcept
atau apakah itu membatasi implementasi di masa depan? Misalnya, Anda mungkin ingin memperkenalkan pengecekan kesalahan argumen ilegal dengan melemparkan pengecualian (misalnya, untuk pengujian unit), atau Anda mungkin bergantung pada kode perpustakaan lain yang dapat mengubah spesifikasi pengecualiannya. Dalam hal ini, lebih aman bersikap konservatif dan mengabaikan noexcept
.
Di sisi lain, jika Anda yakin bahwa fungsi tidak boleh melempar dan itu benar bahwa itu adalah bagian dari spesifikasi, Anda harus mendeklarasikannya noexcept
. Namun, perlu diingat bahwa kompiler tidak akan dapat mendeteksi pelanggaran noexcept
jika implementasi Anda berubah.
- Untuk situasi apa saya harus lebih berhati-hati tentang penggunaan noexcept, dan untuk situasi mana saya bisa lolos dengan noexcept yang tersirat (salah)?
Ada empat kelas fungsi yang harus Anda berkonsentrasi karena mereka akan memiliki dampak terbesar:
- memindahkan operasi (memindahkan operator penugasan dan memindahkan konstruktor)
- operasi swap
- memory deallocators (operator delete, operator delete [])
- destruktor (meskipun ini secara implisit
noexcept(true)
kecuali Anda membuatnya noexcept(false)
)
Fungsi-fungsi ini umumnya harus noexcept
, dan kemungkinan besar implementasi perpustakaan dapat menggunakan noexcept
properti. Misalnya, std::vector
dapat menggunakan operasi pemindahan yang tidak melempar tanpa mengorbankan jaminan pengecualian yang kuat. Jika tidak, ia harus kembali ke elemen penyalinan (seperti yang terjadi pada C ++ 98).
Jenis optimasi ini ada pada level algoritmik dan tidak bergantung pada optimisasi kompiler. Ini dapat memiliki dampak yang signifikan, terutama jika elemen-elemennya mahal untuk disalin.
- Kapan saya dapat secara realistis berharap untuk mengamati peningkatan kinerja setelah menggunakan noexcept? Secara khusus, berikan contoh kode yang kompiler C ++ dapat menghasilkan kode mesin yang lebih baik setelah penambahan noexcept.
Keuntungan dari noexcept
tidak ada spesifikasi pengecualian atau throw()
adalah bahwa standar memungkinkan kompiler lebih banyak kebebasan ketika datang ke stack unwinding. Bahkan dalam throw()
kasus ini, kompiler harus sepenuhnya melepas tumpukan (dan harus melakukannya dalam urutan terbalik yang tepat dari konstruksi objek).
Dalam hal noexcept
ini, di sisi lain, tidak perlu melakukan itu. Tidak ada persyaratan bahwa stack harus dibatalkan (tetapi kompiler masih diperbolehkan untuk melakukannya). Kebebasan itu memungkinkan pengoptimalan kode lebih lanjut karena menurunkan overhead untuk selalu dapat melepaskan tumpukan.
Pertanyaan terkait tentang noexcept, stack unwinding, dan kinerja menjelaskan lebih lanjut tentang overhead saat stack unwinding diperlukan.
Saya juga merekomendasikan buku Scott Meyers "Effective Modern C ++", "Item 14: Deklarasikan fungsi-fungsi kecuali jika mereka tidak akan mengeluarkan pengecualian" untuk bacaan lebih lanjut.
move_if_nothrow
(atau whatchamacallit) akan melihat peningkatan kinerja jika ada ctor langkah noexcept.