以下是将唯一指针作为参数的可能方法,以及它们的相关含义。
(A)按价值计算
Base(std::unique_ptr<Base> n)
: next(std::move(n)) {}
为了让用户调用这个,他们必须做以下事情之一:
Base newBase(std::move(nextBase));
Base fromTemp(std::unique_ptr<Base>(new Base(...));
按值获取唯一指针意味着您正在将指针的所有权转移到相关的函数/对象/等。在构造newBase之后,nextBase被保证为空。你不再拥有对象,你甚至没有指向它的指针。这是一去不复返了。
这是可以确保的,因为我们以值作为参数。Std:move实际上并不移动任何东西;这只是一个花哨的演员阵容。std::move(nextBase)返回一个Base&&,它是对nextBase的r值引用。这就是它所做的。
因为Base::Base(std::unique_ptr<Base> n)的参数是值,而不是r-value引用,所以c++会自动为我们构造一个临时变量。它从我们通过std::move(nextBase)给函数的Base&&中创建了一个std::unique_ptr<Base>。这个临时函数的构造实际上是将值从nextBase移到函数参数n中。
(B)通过非const l-value引用
Base(std::unique_ptr<Base> &n)
: next(std::move(n)) {}
这必须在一个实际的l值(一个命名变量)上调用。它不能像这样调用temporary:
Base newBase(std::unique_ptr<Base>(new Base)); //Illegal in this case.
它的含义与任何其他使用非const引用的含义相同:函数可以声明指针的所有权,也可以不声明。给定以下代码:
Base newBase(nextBase);
不能保证nextBase为空。它可能是空的;可能不会。这实际上取决于Base::Base(std::unique_ptr<Base> &n)想要做什么。正因为如此,仅仅从函数的签名上看不出会发生什么;您必须阅读实现(或相关文档)。
因此,我不建议将其作为接口。
(C)通过const l-value引用
Base(std::unique_ptr<Base> const &n);
我没有展示一个实现,因为你不能从一个const&。通过传递一个参数&,你是说这个函数可以通过指针访问Base,但是它不能存储在任何地方。它不能宣称拥有它。
这很有用。不一定针对你的特定情况,但是能够给别人一个指针,并且知道他们不能(在不违反c++规则的情况下,比如不能放弃const)声明它的所有权总是好的。他们不能储存它。他们可以把它传给其他人,但其他人必须遵守同样的规则。
(D)通过r值引用
Base(std::unique_ptr<Base> &&n)
: next(std::move(n)) {}
这或多或少与“通过非const l-value引用”的情况相同。区别在于两点。
你可以通过一个临时:
Base newBase(std::unique_ptr<Base>(new Base));/ /法律现在. .
当传递非临时参数时,必须使用std::move。
后者才是真正的问题。如果你看到这一行:
Base newBase(std::move(nextBase));
您可以合理地期望,在这一行完成后,nextBase应该为空。它应该从。毕竟,你有std::move坐在那里,告诉你已经发生了移动。
问题是,事实并非如此。它不保证已经从。它可能已经从,但您只能通过查看源代码才能知道。你不能只从函数签名来判断。
建议
(A) By Value: If you mean for a function to claim ownership of a unique_ptr, take it by value.
(C) By const l-value reference: If you mean for a function to simply use the unique_ptr for the duration of that function's execution, take it by const&. Alternatively, pass a & or const& to the actual type pointed to, rather than using a unique_ptr.
(D) By r-value reference: If a function may or may not claim ownership (depending on internal code paths), then take it by &&. But I strongly advise against doing this whenever possible.
如何操作unique_ptr
不能复制unique_ptr。你只能移动它。正确的方法是使用std::move标准库函数。
如果按值获取unique_ptr,则可以自由移动。但是由于std::move,移动实际上不会发生。以下面的陈述为例:
std::unique_ptr<Base> newPtr(std::move(oldPtr));
这实际上是两种说法:
std::unique_ptr<Base> &&temporary = std::move(oldPtr);
std::unique_ptr<Base> newPtr(temporary);
(注意:从技术上讲,上面的代码不能编译,因为非临时r值引用实际上不是r值。这里仅用于演示目的)。
临时只是一个对oldPtr的r值引用。移动发生在newPtr的构造函数中。Unique_ptr的移动构造函数(一个对自身使用&&的构造函数)是实际移动的构造函数。
如果你有一个unique_ptr值,你想把它存储在某个地方,你必须使用std::move来进行存储。