Saya baru saja menyadari sesuatu yang mengganggu. Setiap kali saya menulis metode yang menerima std::string
sebagai parameter, saya membuka diri terhadap perilaku yang tidak jelas.
Sebagai contoh, ini ...
void myMethod(const std::string& s) {
/* Do something with s. */
}
... bisa disebut seperti ini ...
char* s = 0;
myMethod(s);
... dan tidak ada yang bisa saya lakukan untuk mencegahnya (yang saya sadari).
Jadi pertanyaan saya adalah: Bagaimana seseorang mempertahankan diri dari hal ini?
Satu-satunya pendekatan yang terlintas dalam pikiran adalah untuk selalu menulis dua versi dari metode apa pun yang menerima std::string
parameter, seperti ini:
void myMethod(const std::string& s) {
/* Do something. */
}
void myMethod(char* s) {
if (s == 0) {
throw std::exception("Null passed.");
} else {
myMethod(string(s));
}
}
Apakah ini solusi yang umum dan / atau dapat diterima?
EDIT: Beberapa telah menunjukkan bahwa saya harus menerima const std::string& s
alih-alih std::string s
sebagai parameter. Saya setuju. Saya memodifikasi posting. Saya tidak berpikir itu mengubah jawabannya.
c_str
properti objek string ?char* s = 0
tidak terdefinisi. Saya telah melihatnya setidaknya beberapa ratus kali dalam hidup saya (biasanya dalam bentukchar* s = NULL
). Apakah Anda memiliki referensi untuk mendukungnya?std:string::string(char*)
konstruktorconst std::string&
parameter untuk itu ...?)Jawaban:
Saya tidak berpikir Anda harus melindungi diri sendiri. Itu perilaku yang tidak ditentukan di pihak pemanggil. Bukan Anda, itu penelepon yang memanggil
std::string::string(nullptr)
, yang tidak diizinkan. Compiler memungkinkannya dikompilasi, tetapi memungkinkan perilaku tidak terdefinisi lainnya dikompilasi juga.Cara yang sama akan mendapatkan "referensi nol":
Orang yang mereferensi null pointer membuat UB dan bertanggung jawab untuk itu.
Selain itu, Anda tidak dapat melindungi diri sendiri setelah perilaku tidak terdefinisi terjadi, karena pengoptimal berada dalam hak penuh untuk mengasumsikan bahwa perilaku tidak terdefinisi tidak pernah terjadi, sehingga pemeriksaan jika
c_str()
nol dapat dioptimalkan.sumber
Kode di bawah ini memberikan kegagalan kompilasi untuk pass eksplisit
0
, dan kegagalan run-time untukchar*
nilai with0
.Perhatikan bahwa saya tidak menyiratkan bahwa seseorang seharusnya melakukan ini secara normal, tetapi tidak diragukan lagi ada kasus-kasus di mana perlindungan dari kesalahan pemanggil dibenarkan.
sumber
Saya juga mengalami masalah ini beberapa tahun yang lalu dan saya merasa ini adalah hal yang sangat menakutkan. Itu bisa terjadi dengan melewati
nullptr
atau secara tidak sengaja melewati int dengan nilai 0. Ini benar-benar tidak masuk akal:Namun, pada akhirnya ini hanya menyadap saya beberapa kali. Dan setiap kali itu menyebabkan crash langsung ketika menguji kode saya. Jadi tidak ada sesi sepanjang malam akan diperlukan untuk memperbaikinya.
Saya pikir kelebihan fungsi
const char*
adalah ide yang bagus.Saya berharap solusi yang lebih baik dimungkinkan. Namun, tidak ada.
sumber
foo(0)
dan mengkompilasi kesalahan untukfoo(1)
Bagaimana dengan mengubah tanda tangan metode Anda menjadi:
Dengan cara itu pemanggil harus membuat string sebelum mereka menyebutnya, dan kecerobohan yang Anda khawatirkan akan menyebabkan masalah sebelum sampai ke metode Anda, membuat jelas, apa yang orang lain tunjukkan, bahwa itu adalah kesalahan pemanggil bukan milik Anda.
sumber
const string& s
, saya benar-benar lupa. Namun demikian, bukankah saya masih rentan terhadap perilaku yang tidak terdefinisi? Penelepon masih bisa melewati0
, kan?Bagaimana kalau Anda memberikan overload yang dibutuhkan
int
parameter?Anda bahkan tidak perlu mendefinisikan overload. Mencoba menelepon
myMethod(0)
akan memicu kesalahan tautan.sumber
0
memilikichar*
tipe.Metode Anda di blok kode pertama tidak akan pernah dipanggil jika Anda mencoba menyebutnya dengan a
(char *)0
. C ++ hanya akan mencoba membuat string dan itu akan membuang pengecualian untuk Anda. Apakah kamu sudah mencobanya?Lihat? Anda tidak perlu khawatir.
Sekarang jika Anda ingin menangkap ini sedikit lebih anggun, Anda seharusnya tidak menggunakannya
char *
, maka masalahnya tidak akan muncul.sumber
std::string
masuk ke perpustakaan yang digunakan oleh proyek lain di mana saya bukan penelepon. Saya mencari cara untuk menangani situasi dengan anggun dan memberi tahu penelepon (mungkin dengan pengecualian) bahwa mereka mengeluarkan argumen yang salah tanpa merusak program. (Oke, memang, penelepon mungkin tidak menangani pengecualian yang saya lemparkan dan programnya akan macet.)Jika Anda khawatir char * berpotensi pointer nol (mis. Pengembalian dari API C eksternal) jawabannya adalah dengan menggunakan versi const char * dari fungsi alih-alih std :: string one. yaitu
Tentu saja Anda akan memerlukan versi std :: string juga jika Anda ingin mengizinkannya untuk digunakan.
Secara umum yang terbaik adalah mengisolasi panggilan ke API eksternal dan argumen marshal ke dalam nilai yang valid.
sumber