这将执行 1 次复制构造和 3 次移动构造。
- 复制
a 以绑定到lhs。
- 将构造
lhs 移出第一个 +。
- 第一个
+ 的返回值将绑定到第二个 + 的按值 lhs 参数,并带有省略号。
- 第二个
lhs 的返回将引发第二个移动构造。
- 第三个
lhs 的返回将导致第三个移动构造。
- 从第三个
+ 返回的临时值将在sum 构造。
对于上面描述的每个移动结构,都有另一个移动结构可以选择省略。所以你只有保证有 1 个副本和 6 个动作。但在实际操作中,除非你-fno-elide-constructors,否则你将有1个副本和3个动作。
如果你在这个表达式之后没有引用a,你可以进一步优化:
X sum = std::move(a) + b + c + d;
产生 0 个副本和 4 个移动(-fno-elide-constructors 的 7 个移动)。
上面的结果已经通过X 得到证实,该X 检测了复制和移动构造函数。
更新
如果您对优化此功能的不同方法感兴趣,可以从重载 X const& 和 X&& 上的 lhs 开始:
friend X operator+(X&& lhs, X const& rhs) {
lhs += rhs;
return std::move(lhs);
}
friend X operator+(X const& lhs, X const& rhs) {
auto temp = lhs;
temp += rhs;
return temp;
}
这将事情减少到 1 个副本和 2 个移动。如果您愿意限制您的客户通过引用获得 + 的返回,那么您可以从以下重载之一返回 X&&:
friend X&& operator+(X&& lhs, X const& rhs) {
lhs += rhs;
return std::move(lhs);
}
friend X operator+(X const& lhs, X const& rhs) {
auto temp = lhs;
temp += rhs;
return temp;
}
让您减少 1 个副本和 1 个移动。请注意,在此最新设计中,如果您的客户曾经这样做过:
X&& x = a + b + c;
那么x 是一个悬空引用(这就是std::string 不这样做的原因)。