Obtención de una referencia de un bloque try

7

Usando C ++ me gustaría hacer algo como:

  1. Intente obtener una referencia a algo en, por ejemplo, un mapa
  2. Si se lanza, entonces regresa de inmediato
  3. De lo contrario, ve y usa la referencia

Sin embargo, como no podemos declarar un objeto de referencia sin inicializar en C ++, no podemos hacerlo directamente.

Por ejemplo, si estaba feliz de pasar por valor, podría hacerlo:

std::map<char, int> mymap {...};
int x;
try {
    x = m.at('a');
} catch (out_of_range& e) {
    return;
}
// do something with x

Sin embargo, debido a que necesito una referencia, tendría que hacer lo siguiente que no se compilará.

std::map<char, int> mymap {...};
int& x;
try {
    x = m.at('a');
} catch (out_of_range& e) {
    return;
}
// do something with x

Por lo tanto, las opciones que puedo ver son (1), usar un puntero, que me gustaría evitar, o (2), usar un método de mapa diferente que resulte en un código más detallado, como:

std::map<char, int> mymap {...};
auto x_it = m.find('a');
if (x_it == m.end()) {
    return;
}
int& x = x_it->second;
// do something with x

¿Son esas las únicas opciones o hay otra forma de hacerlo de forma ordenada?

    
pregunta Alex 11.08.2016 - 03:18

2 respuestas

11

La forma normal es mover las líneas "entonces algo con x" también dentro del bloque try :

std::map<char, int> mymap {...};
try {
    int& x = mymap.at('a');
    // do something with x
} catch (out_of_range& e) {
    return;
}

Lo bueno de las excepciones es que cuando se lanza una excepción, todo el código entre las ubicaciones de lanzamiento y captura se omite por completo.
Esto significa que puede escribir el código dentro del bloque try { ... } catch sabiendo que todo ha funcionado bien si llega a esa línea.

    
respondido por el Bart van Ingen Schenau 11.08.2016 - 08:52
1

Si quisiera devolver una referencia de both la rama try y la rama catch , sería fácil:

std::map<char, int> mymap {...};
int &x = [&]() -> int & { try {
    return mymap.at('a');
} catch (std::out_of_range& e) {
    return some_default_value;
} } ();
// do something with x

Pero en su caso, solo la rama try devuelve una referencia, por lo que el tipo de retorno del bloque try completo no es un int & sino más bien un optional<int &> . El problema es que C ++ 17 aún no ha salido.

No obstante, optional<int &> es isomorfo a int * , por lo que finalmente usar un puntero aquí parece ser lo correcto. Si no te gusta la sintaxis de -> , puedes simplemente reasignar int &y = *x; .

    
respondido por el Rufflewind 12.08.2016 - 18:50

Lea otras preguntas en las etiquetas