我对以下示例有几个问题:
unique_ptr<A> foo(){
unique_ptr<A> a = make_unique<A>(5);
return move(a);
}
unique_ptr<A>&& foo(){
unique_ptr<A> a = make_unique<A>(5);
return move(a);
}
unique_ptr<int> foo(){
unique_ptr<int> a = make_unique<int>(5);
return a;
}
第一个示例:
为什么编译器允许这样的事情?我们不是返回rvalue裁判吗?为什么编译器允许这样的隐式演员?谁持有基础物体?谁负责在最后销毁它?
第二个示例:
当我这样做时,我会从功能的返回类型中获得垃圾。虽然我认为这是这样做的"正确"方法,但我们不是声明我们正在返回rval ref,并实际上移动我们的对象吗?
第三个示例:
如果删除了unique_ptr
的复制构造函数,那么在此允许此功能的情况下会发生什么?a
是unique_ptr
,我们正在按值返回它,所以不会创建副本?
这是一个快速分解:
-
第一个示例是可以的,但是
std::move(a)
抑制了cooy-eLision。当然,动作比副本更好,但是还没有工作更好。 -
RVALUE参考仍然是一个参考,您需要保持引用的对象的活力。在访问返回的引用之前,引用的本地对象将被破坏。返回rvalue参考很少有用,尽管某些标准功能是这样的(
std::move(x)
,std::forward<T>(x)
,std::declval<T>()
),但是对于这些功能,有一个非本体对象返回。 -
当可能的副本挽救时,对象被隐式移动。这就是副本省略仍然可行的方法。
看来您不知道 copy Elision :在某些情况下,即使更改了程序的语义,也允许编译器允许编译器来填充副本(即副作用副本ctor和dtor不会发生)。有效地,复制省略允许对象立即在正确的位置构造。只有几种情况允许复制省略(确切的规则更为复杂):
- 复制临时对象时。
- 返回本地变量时。
- 扔局部变量时。
- 重新修剪捕获的物体时。
由于在这些情况下未完成副本,因为该对象已经在正确的位置中,因此扩展了移动操作的规则似乎是合理的:当允许复制ELISION时,该对象被隐式移动。净效应是,拥有副本或移动构造函数就足够了。任何体面的编译器既不复制也不会移动,而是要复制/移动构造。