移动后通过右值参考返回

问题描述 投票:1回答:1

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

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 ref,并且实际上是在移动我们的对象吗?

第三个例子:

如果unique_ptr的拷贝构造函数被删除,这里会发生什么允许这个函数? a是一个unique_ptr,我们按价值归还它,所以不会创建副本吗?

c++ smart-pointers rvalue-reference
1个回答
3
投票

这是一个快速的破败:

  1. 第一个例子是好的,但qazxsw poi禁止复制省略。当然,移动比复制更好,但没有工作,但更好。
  2. 右值引用仍然是引用,您需要保持引用的对象保持活动状态。在可以访问返回的引用之前,将销毁引用的本地对象。返回右值引用很少有用,尽管有些标准函数会这样做(std::move(a)std::move(x)std::forward<T>(x)),但是对于这些函数,返回的是非本地对象。
  3. 当可以进行复制省略时,将隐式移动对象。这是复制省略可行的方法。

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

  1. 复制临时对象时。
  2. 返回局部变量时。
  3. 当抛出局部变量时。
  4. 当重新抛出被捕获的物体时。

由于在这些情况下没有复制,因为对象已经在正确的位置,因此扩展规则以移动操作似乎是合理的:当允许复制省略时,隐式移动对象。实际效果是,复制或移动构造函数就足够了。任何体面的编译器既不会复制也不会移动,而是复制/移动构造。

© www.soinside.com 2019 - 2024. All rights reserved.