#[repr(C)]pub struct UniquePtr {
pub _address: u8,
}
Expand description
UniquePtr is a smart pointer that wholly owns a resource. Ownership may be transferred out of a UniquePtr through explicit action, but otherwise the resource is destroyed when the UniquePtr is destroyed.
UniquePtr is similar to C++98’s std::auto_ptr, but it improves upon auto_ptr in one crucial way: it’s impossible to copy a UniquePtr. Copying an auto_ptr obviously can’t copy ownership of its singly-owned resource. So what happens if you try to copy one? Bizarrely, ownership is implicitly transferred, preserving single ownership but breaking code that assumes a copy of an object is identical to the original. (This is why auto_ptr is prohibited in STL containers.)
UniquePtr solves this problem by being movable rather than copyable. Instead of passing a |UniquePtr u| directly to the constructor or assignment operator, you pass |Move(u)|. In doing so you indicate that you’re moving ownership out of |u|, into the target of the construction/assignment. After the transfer completes, |u| contains |nullptr| and may be safely destroyed. This preserves single ownership but also allows UniquePtr to be moved by algorithms that have been made move-safe. (Note: if |u| is instead a temporary expression, don’t use |Move()|: just pass the expression, because it’s already move-ready. For more information see Move.h.)
UniquePtr is also better than std::auto_ptr in that the deletion operation is
customizable. An optional second template parameter specifies a class that
(through its operator()(T*)) implements the desired deletion policy. If no
policy is specified, mozilla::DefaultDelete
Use of UniquePtr proceeds like so:
UniquePtr
UniquePtr
struct S { int x; S(int x) : x(x) {} };
UniquePtr g3, g4(new S(5));
g3 = std::move(g4); // g3 owns the S, g4 cleared
S* p = g3.get(); // g3 still owns |p|
assert(g3->x == 5); // operator-> works (if .get() != nullptr)
assert((g3).x == 5); // also operator (again, if not cleared)
std::swap(g3, g4); // g4 now owns the S, g3 cleared
g3.swap(g4); // g3 now owns the S, g4 cleared
UniquePtr g5(std::move(g3)); // g5 owns the S, g3 cleared
g5.reset(); // deletes the S, g5 cleared
struct FreePolicy { void operator()(void* p) { free(p); } }; UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); int* ptr = g6.get(); g6 = nullptr; // calls free(ptr)
Now, carefully note a few things you can’t do:
UniquePtr
UniquePtr
(Note that changing a UniquePtr to store a direct |new| expression is permitted, but usually you should use MakeUnique, defined at the end of this header.)
A few miscellaneous notes:
UniquePtr, when not instantiated for an array type, can be move-constructed and move-assigned, not only from itself but from “derived” UniquePtr<U, E> instantiations where U converts to T and E converts to D. If you want to use this, you’re going to have to specify a deletion policy for both UniquePtr instantations, and T pretty much has to have a virtual destructor. In other words, this doesn’t work:
struct Base { virtual ~Base() {} }; struct Derived : Base {};
UniquePtr
UniquePtr
UniquePtr is specialized for array types. Specializing with an array type creates a smart-pointer version of that array – not a pointer to such an array.
UniquePtr<int[]> arr(new int[5]); arr[0] = 4;
What else is different? Deletion of course uses |delete[]|. An operator[] is provided. Functionality that doesn’t make sense for arrays is removed. The constructors and mutating methods only accept array pointers (not T*, U* that converts to T*, or UniquePtr<U[]> or UniquePtr) or |nullptr|.
It’s perfectly okay for a function to return a UniquePtr. This transfers the UniquePtr’s sole ownership of the data, to the fresh UniquePtr created in the calling function, that will then solely own that data. Such functions can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where |ptr| is a |T*|, or a UniquePtr |Move()|’d from elsewhere.
UniquePtr will commonly be a member of a class, with lifetime equivalent to that of that class. If you want to expose the related resource, you could expose a raw pointer via |get()|, but ownership of a raw pointer is inherently unclear. So it’s better to expose a |const UniquePtr&| instead. This prohibits mutation but still allows use of |get()| when needed (but operator-> is preferred). Of course, you can only use this smart pointer as long as the enclosing class instance remains live – no different than if you exposed the |get()| raw pointer.
To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| argument. To specify an inout parameter (where the method may or may not take ownership of the resource, or reset it), or to specify an out parameter (where simply returning a |UniquePtr| isn’t possible), use a |UniquePtr&| argument. To unconditionally transfer ownership of a UniquePtr into a method, use a |UniquePtr| argument. To conditionally transfer ownership of a resource into a method, should the method want it, use a |UniquePtr&&| argument.
Fields§
§_address: u8
Trait Implementations§
source§impl PartialEq for UniquePtr
impl PartialEq for UniquePtr
impl Copy for UniquePtr
impl StructuralPartialEq for UniquePtr
Auto Trait Implementations§
impl Freeze for UniquePtr
impl RefUnwindSafe for UniquePtr
impl Send for UniquePtr
impl Sync for UniquePtr
impl Unpin for UniquePtr
impl UnwindSafe for UniquePtr
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Filterable for T
impl<T> Filterable for T
source§fn filterable(
self,
filter_name: &'static str,
) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more