How do I get an owned value out of a `Box`?
Asked Answered
F

1

100

What is the implementation for this function:

fn unbox<T>(value: Box<T>) -> T {
    // ???
}

The only function in the documentation that looks like what I want is Box::into_raw. The following will type check:

fn unbox<T>(value: Box<T>) -> T {
    *value.into_raw()
}

This gives the error error[E0133]: dereference of raw pointer requires unsafe function or block. Wrapping it in an unsafe { ... } block fixes it.

fn unbox<T>(value: Box<T>) -> T {
    unsafe { *value.into_raw() }
}

Is this the correct implementation? If so, why is it unsafe? What does it mean?

Perhaps this question shows my general uncertainty of how Boxs actually work.

Forwhy answered 16/2, 2017 at 3:2 Comment(4)
Note: in your proposed implementation, you are leaking the memory allocated by Box.Enterotomy
@MatthieuM. Currently the Rust compiler doesn't allow moving out of a raw pointer.Saritasarkaria
@TSK: It does, actually. See the core::ptr::read method.Enterotomy
@MatthieuM. I mean OP's example does not leak memory as it won't even compile (there is no ptr::read here).Saritasarkaria
S
135

Dereference the value:

fn unbox<T>(value: Box<T>) -> T {
    *value
}

There's a nightly associated function into_inner you can use as well:

#![feature(box_into_inner)]
fn unbox<T>(value: Box<T>) -> T {
    Box::into_inner(value)
}

Way back in pre-1.0 Rust, heap-allocated values were very special types, and they used the sigil ~ (as in ~T). Along the road to Rust 1.0, most of this special-casing was removed... but not all of it.

This particular specialty goes by the name "deref move", and there's a proto-RFC about supporting it as a first-class concept. Until then, the answer is "because Box is special".

See also:

Scevo answered 16/2, 2017 at 3:6 Comment(9)
Why did I not try that? The Deref trait appears to return an &T. Do I not understand what the * operator does, or are boxes really just special?Forwhy
@Forwhy there's a difference between * and Deref, and boxes are special in this case.Scevo
I wish there was an explicit method instead :(Enterotomy
Would much code break if an explicit method was added and the special behavior was removed? Can this be changed in an edition?Chronicles
@JosephGarvin It couldn't be a method on Box, but you could add an associated function (impl Box { fn whatever(this: Self) -> T }). This could be added immediately if you felt like submitting a PR. Removing the special behavior would likely break far too many things and seems unlikely to be accepted, but potentially possible.Scevo
But when T is a reference to an object trait &dyn T how can we get the inner concret type ?Selene
@tipografieromonah if you have a reference, you can't get an owned value. See Cannot move out of borrowed content / cannot move out of behind a shared reference; Cannot move out of borrowed content when trying to transfer ownership. If you want a reference, see How to get a reference to a concrete type from a trait object?; Why doesn't Rust support trait object upcasting?.Scevo
Thiis one clarified my issue #33687947Selene
It looks like there's an explicit method coming. Box::into_inner() currently in nightly.Allot

© 2022 - 2024 — McMap. All rights reserved.