我正在用 C++ 编写一个小型数值分析库。我一直在尝试使用包括移动语义在内的最新 C++11 特性来实现。我理解以下帖子中的讨论和最佳答案:C++11 rvalues and move semantics chaos (return statement),但有一种情况我仍在尝试解决。
我有一个类,叫做它T
,它完全配备了重载运算符。我也有复制和移动构造函数。
T (const T &) { /*initialization via copy*/; }
T (T &&) { /*initialization via move*/; }
我的客户端代码大量使用运算符,因此我试图确保复杂的算术表达式从移动语义中获得最大收益。考虑以下:
T a, b, c, d, e;
T f = a + b * c - d / e;
如果没有移动语义,我的操作员每次都使用复制构造函数创建一个新的局部变量,因此总共有 4 个副本。我希望通过移动语义我可以将其减少到 2 个副本加上一些移动。在带括号的版本中:
T f = a + (b * c) - (d / e);
每个(b * c)
并且(d / e)
必须以通常的方式使用副本创建临时对象,但是如果我可以利用其中一个临时对象来仅通过移动来累积剩余的结果,那就太好了。
使用 g++ 编译器,我已经能够做到这一点,但我怀疑我的技术可能不安全,我想完全理解为什么。
这是加法运算符的示例实现:
T operator+ (T const& x) const
{
T result(*this);
// logic to perform addition here using result as the target
return std::move(result);
}
T operator+ (T&& x) const
{
// logic to perform addition here using x as the target
return std::move(x);
}
如果没有对 的调用std::move
,则只会const &
调用每个运算符的版本。但是当std::move
如上所述使用时,随后的算术(在最里面的表达式之后)是使用&&
每个运算符的版本执行的。
我知道 RVO 可以被抑制,但在计算量非常大的现实问题上,似乎收益略高于 RVO 的缺乏。也就是说,经过数百万次计算,当我包含std::move
. 虽然老实说,没有它就足够快了。我真的只是想完全理解这里的语义。
有没有好心的 C++ 大师愿意花时间以简单的方式解释我在这里使用 std::move 是否以及为什么是一件坏事?提前谢谢了。