【问题标题】:How to bind a reference to either a const param or a new object?如何绑定对 const 参数或新对象的引用?
【发布时间】:2021-12-27 12:02:07
【问题描述】:

假设我有这个代码:

void MyFunc(const std::string& param) {
  std::string maybe_altered_param;
  if (ConditionIsMet()) {
    maybe_altered_param = AlterParam(param);
  } else {
    maybe_altered_param = param; // <-- unnecessary copy 
  }

  // do stuff with maybe_altered_param
  // maybe_altered_param does not need to be modified further.
}

AlterParam 函数返回字符串的副本,因此当ConditionIsMet 返回 true 时,会创建一个副本以填充 may_altered_pa​​ram。 但是,当ConditionIsMet() 返回 false 时也会进行复制,这是次优的。在第二种情况下,我只想为同一个对象使用另一个名称,而不需要副本或任何类似的东西。

在这种情况下删除不必要的副本的最简单方法是什么?

【问题讨论】:

  • std::string &amp;&amp;maybe_altered_param = ConditionIsMet() ? AlterParam(param) : param; 或(在你的情况下更好?)std::string const &amp;maybe_altered_param = ConditionIsMet() ? AlterParam(param) : param;
  • 这两种情况下,设置后就再也没有修改过吗?
  • 这个额外的副本在配备多赫兹、多核 CPU 的现代 PC 上会减慢多少速度?这个副本会产生什么问题?
  • @EOF 在没有额外副本的情况下可以使用吗?阅读这个问题 (stackoverflow.com/questions/54601265/…) 似乎无论如何都会制作一个额外的副本
  • @EOF:三元运算符会进行复制,因为std::common_type&lt;const std::string&amp;, std::string&gt;std::string

标签: c++ move copy-constructor


【解决方案1】:

我认为您关于引用绑定的问题被误导了。它正在寻找一种语言解决方案来解决本质上是代码组织问题。

您想“使用 Maybe_altered_pa​​ram 做一些事情”,您不想为每个分支重复这些事情(因为 DRY 代码是最好的代码)。那么为什么不重构那一点呢?

static void MyFuncImpl(const std::string& maybe_altered_param) {
  // do stuff with maybe_altered_param
}

void MyFunc(const std::string& param) {
  if (ConditionIsMet()) {
    MyFuncImpl(AlterParam(param));
  } else {
    MyFuncImpl(param);
  }
}

简单易懂。仅当满足条件时才会制作额外的副本,而我们对 maybe_altered_param 所做的事情只拼写一次,由该参数参数化。

可能不是您想要的答案,但我认为值得考虑。

【讨论】:

  • 这绝对值得考虑,但代码并不像我的问题中报告的那样。在调用 conditionIsMet() 之前有一些设置,我需要将一些变量传递给 MyFuncImpl。我认为这可能很容易导致代码更难阅读。有没有办法做相反的事情,例如const std::string& maybe_altered = MaybeAlterParam() 并依靠生命周期延长使其工作?
  • 我不是 100% 确定在这种情况下是否可以延长生命周期 :)
  • @Ant - 我只能解决我看到的代码。并且生命周期延长不会在这里拯救你,因为延长只适用于新对象。您不能将param 插入那里(这会导致您的原始问题,必须在其中复制)。如果您的设置更复杂,那么您仍然可以进行其他重构。一个小的帮助类,它保存共享信息(所以你不需要传递它),它有一个接受字符串参数的成员函数。甚至可以是 lambda(您引用捕获共享数据的地方)。
  • 我的意思是,这样的东西会起作用吗? const std::string& MaybeAlterParam(const std::string& param) { if (ConditionIsMet()) {return AlterParam(param);} return param; } 然后将其用作 void MyFunc(const std::string& param) { const std::string& maybe_altered_pa​​ram = MaybeAlterParam(param);如果 ConditionIsMet 为假,则在返回引用时不会发生复制。如果是真的,在 MaybeAlterParam 中创建的字符串的生命周期是否会延长,直到 Maybe_altered_pa​​ram 超出范围?
  • @Ant - 不,您在此处返回对临时对象的引用。
【解决方案2】:

使用额外的变量,您可以这样做:

void MyFunc(const std::string& param) {
    std::string maybe_altered_param;
    const bool condition_met = ConditionIsMet();
    if (condition_met) {
        maybe_altered_param = AlterParam(param);
    }
    const std::string& ref =
        condition_met ? maybe_altered_param : param; // both are lvalues, so no copy.
    // do stuff with ref
}

【讨论】:

  • +1 是的,我也是这么想的!当 condition_met 为假时,有没有一种简单的方法可以检查这确实不涉及副本?
  • std::string更改为跟踪/记录构造函数调用Demo的类型。
  • 太好了,谢谢! :)
猜你喜欢
  • 2019-07-02
  • 2016-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多