关于以下示例我几乎没有问题:
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
,我们按价值归还它,所以不会创建副本吗?
这是一个快速的破败:
std::move(a)
,std::move(x)
,std::forward<T>(x)
),但是对于这些函数,返回的是非本地对象。您似乎不知道复制省略:在需要复制的某些情况下,即使程序的语义发生变化,编译器也可以忽略复制(即复制文件和文件的副作用不会发生)。实际上,复制省略允许将对象直接构建在正确的位置。只有少数情况允许复制省略(确切的规则更复杂):
由于在这些情况下没有复制,因为对象已经在正确的位置,因此扩展规则以移动操作似乎是合理的:当允许复制省略时,隐式移动对象。实际效果是,复制或移动构造函数就足够了。任何体面的编译器既不会复制也不会移动,而是复制/移动构造。