今天,我们发现了仅在某些平台上间歇性发生的讨厌的错误的原因。归结起来,我们的代码看起来像这样:
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
,但是被调用者的工作不是决定按值还是按引用获取参数吗?
有没有我们不能遵循的规则?