C++API设计和错误处理
C++ API design and error handling
我需要使用.lib文件(MSVC)编写C++API,它由几个从Dll公开的导出C++类组成。根据我对另一个问题的回答,我理解导出的类方法不能使用异常,如果C++API是在一个VC++版本中构建的(比如说2010),而客户端代码是在另一个VCC++版本中编写的。由于异常不能是公共API接口的一部分,我正在寻找另一种错误处理策略。我的限制:我不想使用COM,丰富的错误代码系统(如HRESULT)对我来说是不够的。我希望有一个类似异常的类,它包含错误代码、错误消息和我需要的任何其他信息。此外,我不想为每个VC++版本单独构建。
我目前的做法如下。每个公共类方法都返回枚举值(如ErrorCode)。在方法失败的情况下,像GetLastErrorInfo这样的静态函数会返回指向C++类(比如ErrorInfo)的指针,该类包含到达错误信息。ErrorInfo作为线程特定的数据保存,并包含当前线程中上次调用的错误信息。若上次API调用成功,GetErrorInfo将返回NULL。
考虑这个代码的例外:
尝试{classPtr->DoSomething();cout<lt;classPtr->GetData()<lt;endl;}catch(const MyException和ex){cout<lt;例如GetErrorMessage()<lt;endl;回来}
毫无例外,它看起来是这样的:
ErrorCode结果;int数据;result=classPtr->DoSomething();if(result!=成功){cout<MyClass::GetLastErrorInfo()->GetErrorMessage()<endl;回来}result=classPtr->GetData(data);if(result!=成功){cout<MyClass::GetLastErrorInfo()->GetErrorMessage()<endl;回来}cout<lt;数据<endl;
这看起来不太好。类接口很混乱:现在每个函数都有ErrorCode返回类型。返回值将成为输出参数。是否有更好的方法,允许访问错误信息,并保持干净的公共API接口?
您可能忽略了一个简单的解决方案。唯一的限制是异常不能跨越模块边界。客户端代码本身抛出异常没有问题。因此,在头中提供一个内联函数,比如CheckReturn(),它会抛出富异常。
有关灵感,请查看COM IErrorInfo接口及其相关的_COM_error类。他们解决了完全相同的问题。还要注意MSVC中提供的#import指令,它自动生成小包装函数,这些函数进行调用并在失败返回值上引发异常。但是你不想使用COM,所以它不能直接使用。
如果从.dll返回C++对象,则必须格外小心,因为调用方可能会尝试以复制或删除这些对象的方式使用这些对象。如果调用程序不使用相同的堆(或相同的标准库),那么到处都会出现各种崩溃和内存泄漏。根据我的经验,通过DLL边界传递C++对象是个坏主意。
我会尝试创建API,要求调用方管理所有内存(分配和释放),以便指针的所有权始终是明确的。这会产生更多的工作,因为您需要接受指针,然后用数据填充这些缓冲区,而不是返回C++对象。我还没有看到C++对象在.dll之间安全传递的工作实现。(但我的经验可能有限。)
此外,当您从.dll导出C++类时,C++以外的任何东西都不太可能使用该.dll,因为其他语言对对象有不同的内存布局。即使是不同的C++编译器也可能在使用这些类时出现问题。
重新阅读您的约束,我认为创建COM对象是最好的选择之一,因为它为您提供了灵活性,并能够返回具有复杂数据的对象(尽管不是C++对象)。
这个怎么样:
基本错误数据-你可以扩展你的lib的"其他东西":
namespace MON {
class t_error_description {
public:
t_error_description(const int& code, const std::string& message);
virtual ~t_error_description(); /* << allow any other info via subclass */
public:
virtual void description(std::ostream& stream) const;
/* … */
private:
const int d_code;
const std::string d_message;
};
}
基本错误容器。包装与描述相关的所有内容,这就是客户直接处理的所有内容:
namespace MON {
class t_error {
public:
t_error();
~t_error();
public:
/* or perhaps you'd favor a stream op? */
void description(std::ostream&) const;
/* sets the error - this is a take operation */
void set(const t_error_description* const desc);
void clear();
/* … */
private:
/* trivial construction */
t_auto_pointer<const t_error_description> d_errorDescription;
private:
/* verboten */
t_error(const t_error&);
t_error& operator=(const t_error&);
};
}
基本库调用:
namespace MON {
/* return false on error */
bool DoSomething(t_error& outError) {
if (Foo()) {
outError.set(new t_error_description(ErrorCodeThingy, "blah blah"));
return false;
}
return true;
}
}
客户电话:
MON::t_error err;
if (!MON::DoSomething(err)) {
log << "cannot do anything!nError: ";
err.description(log);
return;
}
- 错误处理.将系统错误代码映射到泛型
- 通过错误处理,在C++中可靠地获得用户十六进制输入
- posix_spawn():使用posix_scawn()时的错误处理问题
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 关于 istream 中的错误处理的问题
- 程序使用的 C 库中的错误处理C++
- C++ 错误检查 fstream open() 命令和一般字符串流错误处理
- 使用std::tie进行类似golang的错误处理,同时返回结果,是否有缺点?(C++11)
- Boost进程"系统"功能中的错误处理
- RPN计算器c++错误处理和多个运算符
- 提升精神 x3 错误处理程序与期望
- 构造函数中的错误处理而不会失败
- 当 C++ 中函数参数的输入类型(类)错误时的错误处理
- 关于 ocilib 错误处理的问题,如何使用 ocilib 正确捕获日志错误?
- 我可以使用 std::optional 进行错误处理吗?
- C++ main() 末尾关于错误处理的错误
- 抽象包装带有异常的 C 错误处理的最佳方法
- vwprintf错误处理(ERRNO显示0)
- C++ 使用枚举进行错误处理
- 在 C++ 中创建自己的错误处理机制