【问题标题】:C++0x T operator+(const T&, T&&) pattern, still needs move?C++0x T operator+(const T&, T&&) 模式,还需要移动吗?
【发布时间】:2011-10-31 17:18:24
【问题描述】:

前段时间有人告诉我,实现二元运算符的常用模式在返回时需要一个最终的move

Matrix operator+(const Matrix &a, Matrix &&b) {
    b += a;
    return std::move(b);
}

但现在有一个特殊规则,即在 return 中,编译器可能会将返回值视为临时值,然后就没有必要这样做了——一个简单的 return b 就足够了。

但话又说回来,b 在这个函数中有一个 name,因此,它是一个 LValue——这会阻碍编译器将其视为临时变量, move 是必需的。

在最新版本的 C++0x 标准中仍然是这种情况吗? 我们需要move 来实现上述模式吗?

【问题讨论】:

  • 根据this answerstd::move 不是必须的。
  • 虽然参数是Matrix&&而不是Matrix可能会有所不同...
  • 复杂的,是的。是的,我认为你是对的。如果它是一个值参数,比如Matrix,那么你就有了一个原始副本——一个临时文件。编译器知道你可以从中获取。对于Matrix&&,我不确定那个-

标签: operator-overloading rvalue-reference c++11


【解决方案1】:

在此示例中您需要显式的 std::move,因为 b 不是非易失性 自动 对象的名称。参考12.8【class.copy】/p31/b1:

  • 在具有类返回类型的函数的返回语句中,当 表达式是非易失性自动对象的名称(其他 比函数或 catch 子句参数)具有相同的 cv- 非限定类型作为函数返回类型,复制/移动操作 可以通过将自动对象直接构造到 函数的返回值

【讨论】:

  • 啊,引用不是对象。我认为你应该强调“对象”而不是“自动”(或两者兼而有之)。
  • 我认为 automatic 在这里是正确的 \em,因为它(大致?确切地说?)转换为“局部变量”。
【解决方案2】:

我不确定为什么这个函数按值返回。这个函数不应该像下面这样返回Matrix&&吗?

Matrix&& operator+(const Matrix &a, Matrix &&b) {
  b += a;
  return std::move(b);
}

这有一个额外的优势,x1 + x2 + x3 + ... + xn 最多创建一个临时的,如果 Matrix 恰好是堆栈分配的,这一点很重要(因为它不会从移动中获得任何收益)。

我认为签名应该是这样的:

Matrix&& operator+(Matrix &&a,      Matrix &&b     );
Matrix&& operator+(const Matrix &a, Matrix &&b     );
Matrix&& operator+(Matrix &&a,      const Matrix &b);
Matrix   operator+(const Matrix &a, const Matrix &b);

【讨论】:

  • 没有。您不应返回&&。这意味着,您返回对其中一个参数的引用,您无法控制它的来源(“不要捡起躺在街上的东西”)。如果您返回Matrix,您可以只在其中一个参数的内容中使用move,并且您可以以完美的性能实现相同的效果。此外,您不需要在(&&, &&) 上重载:您将在那里编写的代码与(&,&&)(&&,&&) 中的代码相同。如果您保留(&&,&&) 重载,编译器将选择其中之一。你只需要 3 个重载。
  • towi:返回对其中一个参数的引用有什么问题?我认为只返回对临时的引用是一个问题。
  • @towi:另外,你有什么证据表明不需要(&&, &&) 过载?我相信ideone.com/qf3Rn 表明它是必要的。
  • 你是对的,我想。 正确的,&& 可以绑定到& 参数,如果没有重载(当然有很多地方需要这样做)。但是我错过了,如果您为您/我们的示例提供重载(&,&&)(&&,&),编译器无法确定哪个更好。但是,如果有一个“更好”的解决方案可以在这里添加重载,只是为了“解惑”编译器,那就太好了。随时在这里编辑ideone.com/9ZhO3
  • 不,您还可以创建从参数返回引用的问题。考虑(以consts 为模)Value& get(map<Key,Value> &d, Value &dfault) { if(not-found) return dfault;}。然后将它与Value &v = get(..., Value{}); cout << v; 一起使用,您的程序将崩溃,因为v 是对您为dfault 创建的temp 的引用。这将在; 消失。当你cout << v它时,它就消失了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多