我现在正在使用libjpeg来保存JPEG图像.如果有错误,libjpeg的默认行为是调用exit(),我想避免,因为它不是我的程序的致命错误.的libjpeg 可以让你使用你自己的错误管理器,并授权,如果您使用自己的error_exit()函数(调用exit()默认情况下),你必须不控制权返回给调用者.libjpeg建议使用setjmp.h来满足此要求而不是exit()程序.
但是,我正在编写一个C++程序,我可以访问异常.这个问题的答案表明从回调中抛出异常是安全的(如明确定义的行为).但它没有提到动态库,并且通常的经验法则是不要在动态库边界之间抛出异常.
这是一个例子:
#include <iostream>
#include <jpeglib.h>
#include <cstdio>
#include <stdexcept>
static void handleLibJpegFatalError(j_common_ptr cinfo)
{
(*cinfo->err->output_message)(cinfo);
throw std::runtime_error("error in libjpeg, check stderr");
}
int main()
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example
try
{
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = handleLibJpegFatalError;
// let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called
// by libjpeg
jpeg_create_compress(&cinfo);
}
catch (...)
{
std::cerr << "Error saving the JPEG!\n";
}
jpeg_destroy_compress(&cinfo);
std::fclose(file);
}
Run Code Online (Sandbox Code Playgroud)
我想知道的是:我可以从这个回调中抛出异常,并在我的应用程序中捕获它,即使libjpeg被编译为动态库吗?libjpeg可能是一个静态或动态库,如果它是一个动态库,它可能是用不同的编译器构建的.但是,抛出并捕获异常的代码肯定会在同一个编译单元中.以上代码是否安全?
仅供参考,我正在为OS X和Windows开发(并考虑到Linux可能性的未来),所以我更感兴趣的是,如果知道这是一般定义良好的行为,而不是特定平台/编译器.
另一个答案适用于此。展开堆栈时不会丢弃任何内容。库是否在内部使用一些疯狂的调用约定也没有关系,只要它不会特别干扰您的 C++ 实现的异常处理结构(它不会作为 C 程序)。我所知道的 C++ 实现没有通过弹出堆栈帧来找到 catch 块(这会使优化成为一场噩梦),它们都维护用于异常处理的内部结构。只要调用链中较低的调用不会与这些结构混淆,堆栈展开将非常适合您的所有个人代码。现在,一般来说,这很可能会使库的内部状态混乱,因为您永远不会将执行返回到库进行清理,
在这种情况下,我会去做。一般来说,我只会从 C 回调中抛出致命异常。
希望有所帮助。
不安全 根据相关非C ++库代码的编译方式,可能不存在必要的展开表。这只是它可能失败的实际原因。概念上的原因是它只是未定义的行为。
您应该遵循文档并使用setjmp/ longjmp来获取对libjpeg代码的调用,然后if (setjmp(...)) { ... }如果要使用异常,则立即在主体中引发异常。