Hoy descubrimos la causa de un error desagradable que solo ocurrió de manera intermitente en ciertas plataformas. En resumen, nuestro código se veía así:
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);
}
}
}
El problema puede parecer obvio en este caso simplificado: Bpasa una referencia a la clave A, que elimina la entrada del mapa antes de intentar imprimirla. (En nuestro caso, no se imprimió, sino que se usó de una manera más complicada) Esto es, por supuesto, un comportamiento indefinido, ya que keyes una referencia pendiente después de la llamada a erase.
Arreglar esto fue trivial: simplemente cambiamos el tipo de parámetro de const string&a string. La pregunta es: ¿cómo podríamos haber evitado este error en primer lugar? Parece que ambas funciones hicieron lo correcto:
Ano tiene forma de saber que sekeyrefiere a lo que está a punto de destruir.Bpodría haber hecho una copia antes de pasarlaA, pero ¿no es el trabajo del destinatario decidir si tomar los parámetros por valor o por referencia?
¿Hay alguna regla que no pudimos seguir?