移动后通过rvalue参考返回



我对以下示例有几个问题:

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的复制构造函数,那么在此允许此功能的情况下会发生什么?aunique_ptr,我们正在按值返回它,所以不会创建副本?

这是一个快速分解:

  1. 第一个示例是可以的,但是std::move(a)抑制了cooy-eLision。当然,动作比副本更好,但是还没有工作更好。

  2. RVALUE参考仍然是一个参考,您需要保持引用的对象的活力。在访问返回的引用之前,引用的本地对象将被破坏。返回rvalue参考很少有用,尽管某些标准功能是这样的(std::move(x)std::forward<T>(x)std::declval<T>()),但是对于这些功能,有一个非本体对象返回。

  3. 当可能的副本挽救时,对象被隐式移动。这就是副本省略仍然可行的方法。

看来您不知道 copy Elision :在某些情况下,即使更改了程序的语义,也允许编译器允许编译器来填充副本(即副作用副本ctor和dtor不会发生)。有效地,复制省略允许对象立即在正确的位置构造。只有几种情况允许复制省略(确切的规则更为复杂):

  1. 复制临时对象时。
  2. 返回本地变量时。
  3. 扔局部变量时。
  4. 重新修剪捕获的物体时。

由于在这些情况下未完成副本,因为该对象已经在正确的位置中,因此扩展了移动操作的规则似乎是合理的:当允许复制ELISION时,该对象被隐式移动。净效应是,拥有副本或移动构造函数就足够了。任何体面的编译器既不复制也不会移动,而是要复制/移动构造。

最新更新