这将执行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 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
不会这样做的原因)。
a+b
的返回值直接构造到operator+(??, c)
中? - Barrylhs
的返回值是不合法的。然而,我也不认为任何编译器的编写者有动机使其合法化(毕竟没有人尝试过这样做)。 - Howard Hinnant