Hari ini kami menemukan penyebab bug buruk yang hanya terjadi sesekali pada platform tertentu. Rebus, kode kami terlihat seperti ini:
class Foo {
map<string,string> m;
void A(const string& key) {
m.erase(key);
cout << "Erased: " << key; // oops
}
void B() {
while (!m.empty()) {
auto toDelete = m.begin();
A(toDelete->first);
}
}
}
Masalahnya mungkin tampak jelas dalam kasus sederhana ini: B
melewatkan referensi ke kunci A
, yang menghapus entri peta sebelum mencoba mencetaknya. (Dalam kasus kami, itu tidak dicetak, tetapi digunakan dengan cara yang lebih rumit) Ini tentu saja perilaku yang tidak terdefinisi, karena key
merupakan referensi yang menggantung setelah panggilan ke erase
.
Memperbaiki ini sepele - kami baru saja mengubah tipe parameter dari const string&
menjadi string
. Pertanyaannya adalah: bagaimana kita bisa menghindari bug ini sejak awal? Tampaknya kedua fungsi melakukan hal yang benar:
A
tidak memiliki cara untuk mengetahui yangkey
mengacu pada hal yang akan dihancurkan.B
bisa membuat salinan sebelum meneruskannyaA
, tetapi bukankah tugas callee untuk memutuskan apakah akan mengambil parameter dengan nilai atau dengan referensi?
Apakah ada aturan yang gagal kita ikuti?