我正在设计一个公开同步和异步操作的C++ API。所有操作可能会失败并且必须报告失败。异步操作必须提供完成时执行延续的方法。我正在尝试以最具可读性和一致性的方式设计API。设计一个结合了同步和异步操作的C++ API
这说明现在的设计我有一个例子:
#include <memory>
#include <future>
using namespace std;
class Error {
public:
Error(int c, string desc) : code(c), description(desc) {}
int code;
string description;
};
template<typename T>
class Callback {
public:
virtual void completed(const T& result, unique_ptr<Error> error) = 0;
};
template<typename T>
class PrintCallback : public Callback<T> {
public:
void completed(const T& result, unique_ptr<Error> error) override {
if (nullptr != error) {
printf("An error has occured. Code: %d Description: %s\n",
error->code, error->description.c_str());
} else {
printf("Operation completed successfully. Result: %s\n",
to_string(result).c_str());
}
}
};
class API {
public:
void asyncOperation(shared_ptr<Callback<int>> callback) {
thread([callback]() {
callback->completed(5, nullptr);
}).detach();
}
int syncOperation(unique_ptr<Error>& error) {
return 5;
}
void asyncFailedOperation(shared_ptr<Callback<int>> callback) {
thread([callback]() {
callback->completed(-1, unique_ptr<Error>(new Error(222, "Async Error")));
}).detach();
}
int syncFailedOperation(unique_ptr<Error>& error) {
error = unique_ptr<Error>(new Error(111, "Sync Error"));
return -1;
}
};
我不喜欢使用使用错误输出参数进行同步操作和同步和异步签名之间的不一致的。 我在辩论两种替代方法:
- 将同步操作视为异步,并让它们接受回调以返回其结果/失败。这种方法在同步和异步操作中更加一致,看起来更干净。另一方面,有一个简单的同步操作与回调工作感觉有点奇怪。
- 使用
std::promise
和std::future
,并使用异常来报告故障。对于异步操作,将返回std::future
,并在发生故障时抛出它的get()
。同步操作只会在发生故障时抛出。这种方法感觉更清晰,因为错误处理不会喧哗方法签名,而异常是在C++中执行错误处理的标准方式。然而,为了得到结果,我必须调用future::get()
,所以如果我不想阻塞,那么我必须启动另一个线程来等待结果。异步操作的继续在实际上在std::promise
上设置结果的线程上运行也很重要。这种方法是这个问题的公认答案 - Synchronous and ASynchronous APIs。
我想知道:
- 如果能够避免替代#2额外的线程。
- 如果替代#2的缺点超过它的优点(特别是额外的线程)。
- 如果还有另一种方法,我没有考虑。
- 哪种方法将被认为是可读性和一致性的最佳选择。
谢谢!
就目前而言,Stack Overflow的问题太广泛了。你可以写一本关于API设计的书! :)但是,我确实有一个挑剔:*“异常是在C++中执行错误处理的标准方法”* - 不,它们不是。取决于上下文,错误代码或断言通常更清晰。 –
[codereview.se]网站更适合于改善现有工作代码的问题。我建议你在咨询他们的[帮助中心](// codereview.stackexchange.com/help/on-topic)后,在那里标记你的问题。 –
@ChristianHackl我觉得这应该是一个非常集中的设计问题。我试图在异步和同步方法之间提出一个关于错误处理的一致性问题,在那里我研究了如何解决它(不同的选择)以及我对它们的担忧。 – galsh83