Senilai seribu kata:
#include<string>
#include<iostream>
class SayWhat {
public:
SayWhat& operator[](const std::string& s) {
std::cout<<"here\n"; // To make sure we fail on function entry
std::cout<<s<<"\n";
return *this;
}
};
int main() {
SayWhat ohNo;
// ohNo[1]; // Does not compile. Logic prevails.
ohNo[0]; // you didn't! this compiles.
return 0;
}
Kompiler tidak mengeluh ketika meneruskan angka 0 ke operator braket menerima string. Sebaliknya, ini mengkompilasi dan gagal sebelum masuk ke metode dengan:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Sebagai referensi:
> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
Tebakanku
Kompiler secara implisit menggunakan std::string(0)
konstruktor untuk memasukkan metode, yang menghasilkan masalah yang sama (google the error di atas) tanpa alasan yang bagus.
Pertanyaan
Apakah ada cara untuk memperbaikinya di sisi kelas, sehingga pengguna API tidak merasakan ini dan kesalahan terdeteksi pada waktu kompilasi?
Artinya, menambahkan kelebihan
void operator[](size_t t) {
throw std::runtime_error("don't");
}
bukan solusi yang baik.
c++
string
std
implicit-conversion
kabanus
sumber
sumber
operator[]()
yang menerimaint
argumen, dan jangan mendefinisikannya.Jawaban:
Alasannya
std::string(0)
valid, adalah karena0
menjadi konstan pointer nol. Jadi 0 cocok dengan konstruktor string yang mengambil pointer. Kemudian kode berjalan bertabrakan dengan prasyarat bahwa seseorang tidak boleh melewatkan pointer nolstd::string
.Hanya literal yang
0
akan ditafsirkan sebagai konstanta penunjuk nol, jika itu adalah nilai waktu berjalan dalamint
Anda tidak akan mengalami masalah ini (karena resolusi kelebihan beban akan mencariint
konversi sebagai gantinya). Secara literal juga1
bukan masalah, karena1
bukan merupakan pointer nol yang konstan.Karena ini adalah masalah waktu kompilasi (nilai literal tidak valid) Anda dapat menangkapnya pada waktu kompilasi. Tambahkan kelebihan formulir ini:
std::nullptr_t
adalah tipenullptr
. Dan itu akan cocok dengan setiap nol pointer konstan, baik itu0
,0ULL
ataunullptr
. Dan karena fungsi ini dihapus, itu akan menyebabkan kesalahan waktu kompilasi selama resolusi kelebihan.sumber
std::string
konstruktor tidak diizinkan oleh standar C ++. Itu perilaku yang tidak terdefinisi, sehingga MSVC dapat melakukan apa pun yang disukainya (seperti melempar pengecualian).Salah satu opsi adalah untuk menyatakan
private
kelebihanoperator[]()
yang menerima argumen integral, dan jangan mendefinisikannya.Opsi ini akan bekerja dengan semua standar C ++ (1998 aktif), tidak seperti opsi seperti
void operator[](std::nullptr_t) = delete
yang valid dari C ++ 11.Membuat
operator[]()
sebuahprivate
anggota akan menyebabkan kesalahan didiagnosis pada contoh AndaohNo[0]
, kecuali ungkapan yang digunakan oleh fungsi anggota ataufriend
kelas.Jika ungkapan itu digunakan dari fungsi anggota atau
friend
kelas, kode akan dikompilasi tetapi - karena fungsi tidak didefinisikan - umumnya build akan gagal (misalnya kesalahan linker karena fungsi yang tidak ditentukan).sumber