移动后通过右值参考返回

时间:2017-12-24 22:02:58

标签: c++ smart-pointers rvalue-reference

关于以下示例我几乎没有问题:

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;
}

第一个例子:

为什么编译器允许这样的事情?我们不是要返回右值参考吗?为什么编译器允许这样的隐式转换?谁持有基础对象?谁负责在最后摧毁它?

第二个例子:

当我这样做时,我从函数的返回类型中获取垃圾。虽然我认为这是“正确”的方法,但是我们不是在宣布我们正在返回一个rval引用,并且实际上是在移动我们的对象吗?

第三个例子:

如果删除unique_ptr的复制构造函数,这里会发生什么允许这个函数? aunique_ptr,我们按值返回,所以不会创建副本吗?

1 个答案:

答案 0 :(得分:3)

这是一个快速的破败:

  1. 第一个例子很好,但std::move(a)禁止cooy-elision。当然,移动比复制更好,但没有工作,但更好。

  2. 右值引用仍然是引用,您需要保持引用的对象处于活动状态。在可以访问返回的引用之前,将销毁引用的本地对象。返回右值引用很少有用,尽管某些标准函数会这样做(std::move(x)std::forward<T>(x)std::declval<T>())但是对于这些函数,返回的是非本地对象。

    < / LI>
  3. 当可以进行复制省略时,会隐式移动对象。这是复制省略可行的方法。

  4. 似乎你不知道 copy elision :在需要拷贝的某些情况下,即使程序的语义发生了变化,编译器也可以忽略副本(即副作用)副本ctor和dtor没有发生)。实际上,复制省略允许将对象直接构建在正确的位置。只有少数情况允许复制省略(确切的规则更复杂):

    1. 复制临时对象时。
    2. 返回本地变量时。
    3. 投掷本地变量时。
    4. 重新抛出被抓物体时。
    5. 由于在这些情况下没有复制,因为对象已经在正确的位置,因此扩展规则以移动操作似乎是合理的:当允许复制省略时,隐式移动对象。实际效果是,复制或移动构造函数就足够了。任何体面的编译器既不会复制也不会移动,而是复制/移动构造。