我正在观看video尼古拉说自动失去移动语义的例子:
@Override
public boolean equals(final Object other) {
if (!(other instanceof Box)) {
return false;
}
return new EqualsBuilder().appendSuper(super.equals(other)).isEquals();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
if (this.hashCode == 0) {
this.hashCode = new HashCodeBuilder().appendSuper(super.hashCode()).toHashCode();
}
return this.hashCode;
}
我在想:
为什么会这样?
guaranteed RVO启动了吗? 这个例子?如果是这样,有什么值得担心的?
答案 0 :(得分:8)
我认为尼古拉本来可以说得更好一点。
当您按auto
返回时,您的函数会返回值(其类型将被推断)。如果std::invoke
返回纯净的右值或x值,那么call
的结果当然会相应地构建(如果可能的话,通过移动)。在这个意义上,我们不会“失去动作语义”。
但是当我们按值返回时,需要创建该值对象。它可以通过移动创建,在某些情况下(which aren't present here)可以省略它,但必须创建它。保证副本省略不允许我们删除创建此对象。
如果std::invoke
给我们一个xvalue(对某事的右值引用),那可能会非常浪费。我们为什么要构造一个返回它的对象?
这就是为什么一两张幻灯片后他说我们应该按decltype(auto)
返回。然后,扣除规则将保留对std::invoke
:
如果它返回一个值,我们就不会更糟。我们自己的call
将返回一个值(可以通过移动std::invoke
的返回值来创建它。)
如果std::invoke
返回左值(X&
)或xvalue(X&&
),则会按原样返回,而不会通过复制或移动创建其他对象。