|
声明为 extern "C" 的 C++ 函数可由 C 程序调用。 C++ COM 服务器可由采用任意数量的不同语言编写的代码使用。 在使用 C++ 实现将由非异常代码调用的可识别异常的公共函数时,C++ 函数不得允许将任何异常传播回调用方。 此类调用方无法捕获或处理 C++ 异常。 程序可能会终止、泄露资源或导致未定义的行为。
我们建议让 extern "C" C++ 函数专门捕获它知道如何处理的所有异常,并根据需要将异常转换为调用方能理解的错误代码。 如果 C++函数并非了解所有可能的异常,它应将 catch(...) 块作为最后一个处理程序。 在这种情况下,最好向调用方报告错误,因为你的程序可能处于未知且无法恢复的状态。
以下示例演示了一个函数,该函数假定可能引发的任何异常是 Win32Exception 或者属于派生自 std::exception 的异常类型。 该函数将捕获这些类型的任何异常并将错误信息作为 Win32 错误代码传递给调用方。
BOOL DiffFiles2(const string& file1, const string& file2)
{
try
{
File f1(file1);
File f2(file2);
if (IsTextFileDiff(f1, f2))
{
SetLastError(MY_APPLICATION_ERROR_FILE_MISMATCH);
return FALSE;
}
return TRUE;
}
catch(Win32Exception& e)
{
SetLastError(e.GetErrorCode());
}
catch(std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return FALSE;
}
从异常转换为错误代码时,有一个潜在问题:错误代码包含的信息通常不及异常可存储的信息丰富。 要解决此问题,可为每个可能引发的具体异常类型提供一个 catch 块,并在异常转换为错误代码前执行日志记录以记录异常的详细信息。 如果多个函数都使用同一组 catch 块,此方法可能产生重复代码。 避免代码重复的一个好方法是,将这些块重构到一个实现 try 和 catch 块并接受 try 块中调用的函数对象的专用实用工具函数中。 在每个公用函数中,将代码传递到实用工具函数以作为 lambda 表达式。
template<typename Func>
bool Win32ExceptionBoundary(Func&& f)
{
try
{
return f();
}
catch(Win32Exception& e)
{
SetLastError(e.GetErrorCode());
}
catch(const std::exception& e)
{
SetLastError(MY_APPLICATION_GENERAL_ERROR);
}
return false;
}
以下示例演示如何编写函数定义的 lambda 表达式。 lambda 表达式通常比调用命名函数对象的代码更容易内联读取。
bool DiffFiles3(const string& file1, const string& file2)
{
return Win32ExceptionBoundary([&]() -> bool
{
File f1(file1);
File f2(file2);
if (IsTextFileDiff(f1, f2))
{
SetLastError(MY_APPLICATION_ERROR_FILE_MISMATCH);
return false;
}
return true;
});
}
若要详细了解 lambda 表达式,请参阅 lambda 表达式。
|
|