今日、特定のプラットフォームでのみ断続的に発生する厄介なバグの原因を発見しました。要約すると、コードは次のようになりました。
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);
}
}
}
この単純化されたケースでは、問題は明らかなように見えB
ます。キーへの参照を渡してA
、マップエントリを削除してから印刷しようとします。以来、これはもちろん、未定義の動作である(私たちの場合は、それが印刷されなかったが、より複雑な方法で使用される)key
への呼び出し後にダングリング参照ですerase
。
これを修正するのは簡単でしconst string&
たstring
。パラメータタイプをからに変更しました。問題は、そもそもどうやってこのバグを回避できたのでしょうか?両方の機能が正しいことをしたようです:
A
key
破壊しようとしているものを参照していることを知る方法がありません。B
に渡す前にコピーを作成できたかもしれA
ませんが、値または参照によってパラメータを取るかどうかを決定するのは呼び出し先の仕事ではありませんか?
従わなかったルールはありますか?