No estoy preguntando si es seguro que una excepción en C++ se propague a través del código C, ni qué sucede cuando ocurre eso. He leído las siguientes preguntas en SO (1, 2, 3) y . Estoy preguntando cómo proceder para:Un mecanismo para asegurar la propagación de excepciones al mezclar el código C y C++
- evitar fugas ninguna excepción C++ hacia el código C (esto implica la captura de todas las excepciones en la tierra C++ antes de llamar a código C)
- también ser capaz de detectar las excepciones fuera de la Código C (en un código C++ más alto).
Vamos a ilustrar mi idea:
Say libfoo
es una biblioteca de C, que yo quiero usar en mi programa bar
C++. libfoo
necesita una función de devolución de llamada foo_callback
que debo proporcionar. Las funciones y los métodos utilizados en mi devolución de llamada puede lanzar una excepción, por lo que escribieron:
void my_callback(void)
{
try
{
// Do processing here.
}
catch(...)
{
// Catch anything to prevent an exception reaching C code.
// Fortunately, libfoo provides a foo_error function to
// signal errors and stop processing.
foo_error() ;
}
}
Y entonces yo uso mi devolución de llamada como se muestra a continuación:
// The bar program.
int main()
{
// Use libfoo function to set the desired callback
foo_set_callback(&my_callback) ;
// Start processing. This libfoo function uses internally my_callback.
foo_process() ;
// Check for errors
if(foo_ok())
{
// Hurray !
}
else
{
// Something gone wrong.
// Unfortunately, we lost the exception that caused the error :(
}
}
Lo que yo quiero es ser capaz de atrapar las excepciones lanzadas desde my_callback
en la función main
, sin tener la excepción de propagarse a través de libfoo
(Sí, es una especie de excepción cuántica que experimenta quantum tunnelling a través del código C).
Así que el código me gustaría usar:
void my_callback(void)
{
try
{
// Do processing here.
}
catch(...)
{
// Catch anything to prevent an exception reaching C code.
// We save the exception using (the magic) ExceptionHolder.
ExceptionHolder::Hold() ;
// Call foo_error function to signal errors and stop processing.
foo_error() ;
}
}
// The bar program.
int main()
{
// Use libfoo function to set the desired callback
foo_set_callback(&my_callback) ;
try
{
// Start processing. This libfoo function uses internally my_callback.
foo_process() ;
// Once gone out of the C land, release any hold exception.
ExceptionHolder::Release() ;
}
catch(exception & e)
{
// Something gone wrong.
// Fortunately, we can handle it in some manner.
}
catch(/*something else */)
{
}
// ...
}
Dadas las siguientes limitaciones:
libfoo
es de código cerrado, escrito en C y proporcionado en formato compilado a partir de un proveedor. Las pruebas realizadas en la biblioteca mostraron que las excepciones no pueden propagarse a través de ella. No tengo acceso a los archivos fuente ni puedo obtener una versión compilada que admita excepciones.- La función de devolución de llamada hace un uso extensivo del código C++ que usa excepciones. Todo el manejo de errores se basa en el mecanismo de excepción. De ninguna manera, simplemente puedo usar el código que se traga todas las excepciones.
- Sin multihilo involucrado.
- Sin soporte de C++ 0x.
Mis preguntas:
- ¿Es ya resuelto por alguna biblioteca o un poco de magia C++ (como
boost
), o incluso C++ 0x? - Si no es así, ¿cómo puedo escribir un ExceptionHolder que funcione con cualquier tipo de excepción? Estoy cómodo con C++ pero no he encontrado la manera de escribir un ExceptionHolder confiable y fácil de usar que funcione con cualquier tipo de excepción.
Muchas gracias por cualquier consejo!
EDIT: He añadido una respuesta con un poco de implementación de la celebración de excepción/mecanismo de liberación. Todos los críticos o proposiciones son bienvenidos.
Probablemente valga la pena mencionar que el enfoque de impulso refleja bastante directamente los mecanismos que se han introducido en la biblioteca estándar en C++ 0x para abordar el mismo problema. Son un poco más mágicos, por lo que puedo decir. – ben
Gracias! Investigaré tu proposición, ya que parece prometedor :) – overcoder
Después de jugar con 'boost :: enable_current_exception', encontré que tiene poca flexibilidad, ya que obliga al usuario a rodear todas las excepciones con' boost :: enable_current_exception' en todos los posibles sitios de lanzamiento antes de poder usarlo. No me puedo permitir esta refactorización * major * en la base de código actual. – overcoder