在返回结果的同时使用 std::tie 进行类似 golang 的错误处理是否有缺点? (C++11)

Are there downsides with using std::tie for golang-like error-handling while also returning a result? (C++11)

在一种常见的错误处理方式中,仍然return一个值是使用元组。

我想知道在异常不适用时使用 std::tie 在 C++ 中做同样的事情是否是个好主意。

喜欢

std::tie(errorcode, data) = loadData();
if(errorcode)
  ...//error handling

这样做有什么缺点吗(性能或其他方面)?我想 return 价值优化并没有真正产生影响,但也许我错了。

我能看到的一个潜在问题案例是在交叉编译器中的使用 API 但这并不特定于此用途。

我目前的做法是

errorcode = loadData(&data);
if(errorcode)
  ...//error handling

但这允许传入数据值。

错误码本身是已经定义好的,我无法更改。

编辑:我using/have使用C++11

错误处理有多种相互竞争的策略。我不会讨论它,因为它超出了问题的范围,但是 return 错误代码的错误处理只是一种选择。考虑像 std::optional 或异常这样的替代方案,它们在 C++ 中都很常见,但在 Go 中并不常见。

如果您有一个旨在 return Go 风格的错误代码加值的函数,那么您的 std::tie 解决方案在 C++11 或 C+14 中完全没问题,尽管在 C++17 中,您更喜欢结构化绑定。

Are there any downsides to doing so (performance or otherwise)?

是的。使用 tie 时,需要复制或移动返回值,如果避免 tie:

则不需要
auto result = loadData();
if (std::get<0>(result))
    ...//error handling

当然,如果您稍后将数据复制或移动到其他地方,例如

data = std::move(std::get<1>(result));

然后使用 tie 因为它更短。

有时候输出参数很方便。假设 loadData returns std::vector<T> 并在循环中被调用:

std::pair<ErrorCode, std::vector<T>> loadData();

for (...) {
    ErrorCode errorcode;    
    std::vector<T> data;
    std::tie(errorcode, data) = loadData();
}

在这种情况下,loadData 将不得不在每次迭代时分配内存。但是,如果将 data 作为输出参数传递,则可以重复使用之前分配的 space:

ErrorCode loadData(std::vector<T>&);

std::vector<T> data;
for (...) {
    ErrorCode errorcode = loadData(data);
}

如果以上内容不重要,那么您可能想看看 expected<T, E>。它代表

  • 一个T类型的值,期望值类型;或
  • E 类型的值,发生意外结果时使用的错误类型。

使用 expectedloadData() 签名可能如下所示:

expected<Data, ErrorCode> loadData();

C++11 实现可用:https://github.com/TartanLlama/expected