unique_ptr<T>和unique_ptr<T>&&之间的区别

5
以下两种声明有何区别,我应该在什么情况下选择其中一种?

int* ptr;

int *ptr;

void f(unique_ptr<T> x);
void f(unique_ptr<T> &&x);

在我看来,这两种方式都意味着f()接管了指向的对象,但我见过有人同时使用它们。我认为第一种方式应该是标准的,而第二种方式则被认为是一种不好的做法。


第一个是按值传递的,因此由于它是不可复制的,所以无法与 unique_ptr 一起编译。 - Jonathan Potter
2
@JonathanPotter - 你错了,如果你使用move()函数它是可以编译的。 - tohava
Rvalue引用简介 - Maxim Egorushkin
2
在第一种情况下,f确实拥有所有权,而在第二种情况下,f可能会拥有所有权。 - Jarod42
1
你甚至不需要使用move,它只需要是一个r-value,例如函数返回值或直接调用构造函数。 - Benjamin Lindley
1个回答

7
第二个版本,使用引用传递的方式,效率略高一些,因为不需要为函数参数构造单独的对象。在通用库代码中,您会发现这种风格,其中不希望对用户施加任何不必要的成本。
第一个版本更容易阅读和记忆,并允许稍微更一般的建议是“按值传递想要拥有的东西”。尽管该建议在您的情况下并不完美适用,但在其他情况下它确实适用。考虑一个拥有字符串的类:
struct Foo
{
    std::string s_;
    Foo(std::string s) : s_(std::move(s)) {}
};

通过按值传递构造函数参数,您现在可以从左值和右值字符串构造Foo,并且您将复制或移动的决定留给std::string的构造函数,而不是自己担心。这减少了复杂性(想象一下你有五个这样的参数)。
作为一般建议的最后一句话,请记住,C++标准库认为绑定到右值引用的任何值都是未别名的,即仅由该引用引用,没有其他人。这是一个重要的“隐藏”语义假设。因此,尽管右值引用是一个引用,您原则上可以使用它来引用一些共享状态,但不要过度使用它,因为这将是意外和令人惊讶的。

+1 作为最后一个单词(如果没有其他内容)。 - Angew is no longer proud of SO
一个旁观者的观点:“按值传递和移动”很容易教授。它很直接明了(你有一个值,最好从中移动)。相比之下,许多新手在使用右值引用时会感到非常困惑,并且不意识到他们仍然需要移动 -- 即使程序员打算请求移动语义,忘记移动可能会悄悄地降低性能。 - Kerrek SB
1
另一个需要注意的是,如果你传递一个左值(使用clang),编译器返回的错误信息类型:对于按值参数,你会得到“call to implicitly-deleted copy constructor of 'std::unique_ptr<T>'”,而对于按右值引用版本,则会得到“no matching function for call to 'f'”。在我看来,第一种错误信息更清晰明了。 - klaus triendl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接