Struct mozjs::jsapi::mozilla::UniquePtr

source ·
#[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 is used – which will either |delete| or |delete[]| the resource, depending whether the resource is an array. Custom deletion policies ideally should be empty classes (no member fields, no member fields in base classes, no virtual methods/inheritance), because then UniquePtr can be just as efficient as a raw pointer.

Use of UniquePtr proceeds like so:

UniquePtr g1; // initializes to nullptr g1.reset(new int); // switch resources using reset() g1 = nullptr; // clears g1, deletes the int

UniquePtr g2(new int); // owns that int int* p = g2.release(); // g2 leaks its int – still requires deletion delete p; // now freed

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 b1; b1 = new int; // BAD: can only assign another UniquePtr int* ptr = b1; // BAD: no auto-conversion to pointer, use get()

UniquePtr b2(b1); // BAD: can’t copy a UniquePtr UniquePtr b3 = b1; // BAD: can’t copy-assign a 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 b1; // BAD: DefaultDelete and DefaultDelete don’t interconvert UniquePtr d1(std::move(b));

UniquePtr b2; UniquePtr<Derived, DefaultDelete> d2(std::move(b2)); // okay

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 Clone for UniquePtr

source§

fn clone(&self) -> UniquePtr

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for UniquePtr

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
source§

impl PartialEq<UniquePtr> for UniquePtr

source§

fn eq(&self, other: &UniquePtr) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Copy for UniquePtr

source§

impl StructuralPartialEq for UniquePtr

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.