我们有一个代码库,该代码库大量使用了参数,因为每个函数都可能因错误枚举而失败。
这变得非常困惑,有时代码也不可读。

我想消除这种模式,并采用一种更现代的方法。

目标是转变:

error_t fn(param_t *out) {
    //filling 'out'
}
param_t param;
error_t err = fn(&param);

变成类似:
std::expected<error_t, param_t> fn() {
    param_t ret;
    //filling 'ret'
    return ret;
}
auto& [err, param] = fn();

下列问题是为了说服自己和他人,这种改变是最好的:
  • 我知道在标准级别上,NRVO不是强制性的(与c++ 17中的RVO不同),但是实际上有没有机会在任何主要编译器中都不会发生?
  • 使用out参数代替NRVO有什么好处?
  • 假设发生NRVO,生成的程序集是否有重大变化(假设优化了expected实现[也许 bool(boolean) 值表示错误是否完全消失])?
  • 最佳答案

    首先,有一些假设:

  • 我们正在查看未内联的函数。在这种情况下,几乎可以保证绝对相等。
  • 我们将假定函数的调用站点在使用返回值之前实际检查了错误情况。
  • 我们将假定未使用部分数据对返回值进行预初始化。
  • 我们将假设我们在这里只关心优化的代码。

  • 正在建立:



    假设此时正在执行NRVO是一个安全的选择。我敢肯定有人会想到不会发生这种情况,但是我通常相信,在几乎所有用例中,NRVO都会在当前的现代编译器上执行。

    话虽如此,我永远不会依赖此行为来实现程序的正确性。即我不会因为NRVO而不会调用它,而不会产生带有副作用的怪异的复制构造函数。



    通常没有,但是像C++中的所有事物一样,在某些极端情况下可能会出现这种情况。用于最大化缓存一致性的显式内存布局将是“按指针返回”的好用例。



    这个问题对我来说意义不大。 expected<>的行为更像是variant<>而不是tuple<>,因此“表示是否发生错误的 bool(boolean) 值完全消失”实际上没有任何意义。

    话虽这么说,我认为我们可以使用std::variant来估算:

    https://godbolt.org/g/XpqLLG

    我认为这是“不同的”,但不一定好或坏。

    10-06 07:49