Di akhir ceramah Scott Schurr "Memperkenalkanconstexpr
" di CppCon , dia bertanya "Apakah ada cara untuk meracuni suatu fungsi"? Dia kemudian menjelaskan bahwa ini dapat dilakukan (meskipun dengan cara yang tidak standar) dengan:
- Menempatkan a
throw
dalam suatuconstexpr
fungsi - Menyatakan belum terselesaikan
extern const char*
- Mereferensikan yang belum terselesaikan
extern
dithrow
Saya merasa bahwa saya sedikit keluar dari kedalaman saya di sini, tetapi saya penasaran:
- Apa artinya "meracuni suatu fungsi"?
- Apa signifikansi / kegunaan dari teknik yang dia uraikan?
constexpr
fungsi tersebut dievaluasi pada waktu kompilasi.constexpr
fungsi dapat digunakan baik pada waktu kompilasi atau pada waktu berjalan. Jadi ini adalah cara untuk memaksanya agar tidak dapat digunakan saat dijalankan? Kapan itu berguna?constexpr
fungsi sering kali bukan implementasi yang paling efisien karena adanya batasan, jadi orang mungkin tidak ingin dievaluasi pada waktu proses; atau, mungkin itu kasus kesalahan (seperti pada contohnya).Jawaban:
Secara umum ini mengacu pada membuat suatu fungsi tidak dapat digunakan, misalnya jika Anda ingin melarang penggunaan alokasi dinamis dalam suatu program, Anda dapat "meracuni"
malloc
fungsi tersebut sehingga tidak dapat digunakan.Dalam video, dia menggunakannya dengan cara yang lebih spesifik, yang jelas jika Anda membaca slide yang ditampilkan ketika dia berbicara tentang meracuni fungsi, yang mengatakan "Cara untuk memaksa waktu kompilasi saja?"
Jadi dia berbicara tentang "meracuni" fungsi untuk membuatnya tidak bisa dipanggil pada saat dijalankan, jadi itu hanya bisa dipanggil dalam ekspresi konstan. Tekniknya adalah memiliki cabang dalam fungsi yang tidak pernah diambil ketika dipanggil dalam konteks waktu kompilasi, dan membuat cabang tersebut berisi sesuatu yang akan menyebabkan kesalahan.
Sebuah
throw
ekspresi diperbolehkan dalam fungsi constexpr, selama itu tidak pernah tercapai selama doa saat kompilasi dari fungsi (karena Anda tidak bisa membuang pengecualian pada saat kompilasi, itu operasi inheren dinamis, seperti mengalokasikan memori). Jadi ekspresi lemparan yang merujuk ke simbol yang tidak ditentukan tidak akan digunakan selama pemanggilan waktu kompilasi (karena itu akan gagal untuk dikompilasi) dan tidak dapat digunakan pada waktu proses, karena simbol yang tidak ditentukan menyebabkan kesalahan penaut.Karena simbol tak terdefinisi tidak "digunakan-odr" dalam pemanggilan fungsi waktu kompilasi, dalam praktiknya kompilator tidak akan membuat referensi ke simbol, jadi tidak masalah jika tak terdefinisi.
Apakah itu berguna? Dia mendemonstrasikan bagaimana melakukannya, tidak harus mengatakan itu ide yang bagus atau berguna secara luas. Jika Anda memiliki kebutuhan untuk melakukannya karena alasan tertentu maka tekniknya mungkin dapat menyelesaikan masalah Anda. Jika Anda tidak membutuhkannya, Anda tidak perlu mengkhawatirkannya.
Salah satu alasan mengapa ini mungkin berguna adalah ketika versi waktu kompilasi dari beberapa operasi tidak seefisien mungkin. Ada batasan pada jenis ekspresi yang diizinkan dalam fungsi constexpr (terutama di C ++ 11, beberapa batasan telah dihapus di C ++ 14). Jadi, Anda mungkin memiliki dua versi fungsi untuk melakukan penghitungan, yang optimal, tetapi menggunakan ekspresi yang tidak diizinkan dalam fungsi konstekspr, dan yang merupakan fungsi konsteks yang valid, tetapi akan berkinerja buruk jika dipanggil saat run- waktu. Anda bisa meracuni yang sub-optimal untuk memastikannya tidak pernah digunakan untuk panggilan run-time, memastikan versi yang lebih efisien (non-constexpr) digunakan untuk panggilan run-time.
NB Performa fungsi constexpr yang digunakan pada waktu kompilasi tidak terlalu penting, karena ia tidak memiliki run-time overhead. Ini mungkin memperlambat kompilasi Anda dengan membuat kompiler melakukan pekerjaan ekstra, tetapi itu tidak akan menimbulkan biaya kinerja waktu proses.
sumber
'Meracuni' sebuah pengenal berarti bahwa setiap referensi ke pengenal setelah 'keracunan' adalah kesalahan kompiler yang sulit. Teknik ini dapat digunakan, misalnya, untuk deprecation (fungsi IS tidak digunakan lagi, jangan pernah menggunakannya!).
Dalam GCC tradisional ada pragma untuk ini:
#pragma GCC poison
.sumber