【问题标题】:optimizing binary arithmetic operations using move semantics使用移动语义优化二进制算术运算
【发布时间】:2014-01-02 17:55:21
【问题描述】:

我正在用一个简单的Vector 类试验rvalue 引用,试图消除二进制操作中不需要的临时对象。经过一番挣扎,我发现operator+()有以下两个重载:

// overload called if right = lvalue and left = lvalue/rvalue
friend Vector<T> operator+(Vector<T> a, const Vector<T>& b) {
  a += b;
  return a;
}

// overload called if right = rvalue and left = lvalue/rvalue
friend Vector<T> operator+(const Vector<T>& a, Vector<T>&& b) {
  b += a;
  return std::move(b);
}

我可以确保在像auto x = a+b+c+d+...; 这样的表达式中,只要至少ab 是临时的,将调用移动构造函数而不创建任何新的临时变量。

另一方面,即使ab(比如d)之后的值之一是lvalue,从技术上讲,这应该足以避免复制。编译器是否可以通过扫描给定表达式以找到至少一个临时表达式并根据该值开始调用 operator+ 来进行任何优化?

示例 1:

#include "vector.h"

Vector<double> get() {
  return {0, 1, 2, 6};
}
int main (){
  auto a = get();
  auto b = get();
  auto c = a + get() + b;
  std::cout << c << std::endl;

  return 0;
}

输出:

calling move ctor
calling move ctor
[0, 3, 6, 18]

示例 2:

#include "vector.h"

Vector<double> get() {
  return {0, 1, 2, 6};
}
int main (){
  auto a = get();
  auto b = get();
  auto c = a + b + get();
  std::cout << c << std::endl;

  return 0;
}

输出:

calling copy ctor
calling move ctor
[0, 3, 6, 18]

【问题讨论】:

  • 可以用sum(a,b,get() )代替operator+(a, operator+(b, get() ) )吗?这样你就有了表达式每个部分的 lvale/rvalue 信息,但是一旦你开始处理任意表达式,它就会变得丑陋(我正在考虑构建一个表达式树,就像在 eigen.tuxfamily.org/dox/TopicInsideEigenExample.html 中一样)。

标签: c++ optimization c++11 move-semantics rvalue-reference


【解决方案1】:

我猜答案是否定的。在你的代码中

auto c = a + b + get();

编译器必须首先在 a 和 b 上调用 operator+()。我认为这个执行顺序是在语言规范中预定义的。编译器不应该先执行 b + get(),因为不同的执行顺序会导致 (a + b + get()) 的返回值不同,以及不同的副作用。所以执行顺序应该保持不变。

编译器首先可以用 a + b 部分做些什么吗?由于 a 和 b 都是左值,编译器必须选择一个接受两个左值参数的函数。并不是编译器开发人员不能添加新的优化,而是编译器应该只按照语言指定的方式进行。假设编译器将函数的 r 值版本用于 a + b。然后,在你的函数中,a 或 b 将被修改(因为它们是 r 值),这是无意的:为什么我们需要修改操作数以获得它们的总和?

如果您愿意在函数中修改 a 和 b,只需在调用函数之前将它们转换为 r 值,例如 std::move(a) + std::move(b) + get()

希望这会有所帮助。

【讨论】:

  • 我猜你的意思是std::move(a)而不是a.move()
  • 您可以随时编辑您的答案。反正我修好了。
  • 哇,我不知道有人也可以编辑其他人的答案!
猜你喜欢
  • 1970-01-01
  • 2019-03-25
  • 2013-02-27
  • 2022-06-12
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 2017-12-19
  • 1970-01-01
相关资源
最近更新 更多