本文介绍了C++ API 设计和错误处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用 .lib 文件 (MSVC) 编写 C++ API,它由从 Dll 公开的几个导出的 C++ 类组成.从我对另一个问题的回答中我了解到,导出的类方法不能使用异常,如果 C++ API 是在一个 VC++ 版本(假设是 2010)中构建的,并且客户端代码是在另一个 VC++ 版本中编写的.由于异常不能成为公共 API 接口的一部分,我正在寻找另一种错误处理策略.我的限制:我不想使用COM,丰富的错误代码系统(如HRESULT)对我来说还不够.我想要一个类似异常的类,其中包含错误代码、错误消息和我需要的任何其他信息.另外,我不想为每个 VC++ 版本单独构建.

我目前的方法如下.每个公共类方法都返回枚举值(如 ErrorCode).在方法失败的情况下,像 GetLastErrorInfo 这样的静态函数返回指向 C++ 类的指针(假设 ErrorInfo),其中包含到达错误信息.ErrorInfo 保留为线程特定的数据,并包含来自当前线程中最后一次调用的错误信息.如果上次 API 调用成功,则 GetErrorInfo 返回 NULL.

考虑此代码有例外:

尝试{classPtr->DoSomething();cout<<classPtr->GetData() <

无一例外,它看起来像这样:

ErrorCode 结果;整数数据;结果 = classPtr->DoSomething();如果(结果!=成功){cout << MyClass::GetLastErrorInfo()->GetErrorMessage() << endl;返回;}结果 = classPtr->GetData(data);如果(结果!=成功){cout << MyClass::GetLastErrorInfo()->GetErrorMessage() << endl;返回;}cout<<数据<

这看起来不太好.类接口很乱:现在每个函数都有 ErrorCode 返回类型.返回值成为输出参数.有没有更好的方法,允许访问错误信息,并保持干净的公共 API 接口?

解决方案

您可能忽略了一个简单的解决方案.唯一的限制是异常不能跨越模块边界.客户端代码本身抛出异常没有问题.所以在标头中提供一个内联函数,比如 CheckReturn(),它会抛出丰富的异常.

要获得灵感,请查看 COM IErrorInfo 接口及其关联的_com_error 类.他们解决了完全相同的问题.另请注意 MSVC 中可用的 #import 指令,它会自动生成进行调用并在失败返回值上引发异常的小型包装函数.但是您不想使用 COM,因此不能直接使用.

I need to write C++ API, which consists of several exported C++ classes exposed from Dll, using .lib files (MSVC). From the answer to my another question I understand, that exported class methods cannot use exceptions, in the case if C++ API is built in one VC++ version (let's say 2010), and client code is written in another VC++ version. Since exceptions cannot be a part of public API interface, I am looking for another error handling strategy. My restrictions: I don't want to use COM, and rich error code system (like HRESULT) is not enough for me. I want to have exception-like class which contains error code, error message and any other information that I need. Also, I don't want to make separate build for every VC++ version.

My current approach is the following. Every public class method returns enumerated value (like ErrorCode). In the case the method fails, static function like GetLastErrorInfo returns the pointer to C++ class (let's say ErrorInfo), which contains reach error information. ErrorInfo is kept as thread-specific data, and contains error information from the last call in the current thread. If last API call succeeded, GetErrorInfo returns NULL.

Consider this code with exceptions:

try
{
    classPtr->DoSomething();
    cout << classPtr->GetData() << endl;
}
catch(const MyException& ex)
{
    cout << ex.GetErrorMessage() << endl;
    return;
}

Without exceptions, it looks like this:

ErrorCode result;
int data;
result = classPtr->DoSomething();
if ( result != Success )
{
    cout << MyClass::GetLastErrorInfo()->GetErrorMessage() << endl;
    return;
}
result = classPtr->GetData(data);
if ( result != Success )
{
    cout << MyClass::GetLastErrorInfo()->GetErrorMessage() << endl;
    return;
}
cout << data << endl;

This doesn't look good. Class interface is messy: every function now has ErrorCode return type. Return values become output parameters. Is there better approach, that allows to have reach error information, and to keep clean public API interface?

解决方案

You are possibly overlooking a simple solution. The only restriction is that an exception cannot cross a module boundary. There is no problem with the client code itself throwing an exception. So provide an inline function in the header, say CheckReturn(), that throws the rich exception.

For inspiration, look at the COM IErrorInfo interface and its associated _com_error class. They solve the exact same problem. Also note the #import directive available in MSVC, it auto-generates the small wrapper functions that make the call and throw the exception on a failure return value. But you don't want to use COM so that's not directly usable.

这篇关于C++ API 设计和错误处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 03:49
查看更多