Auto merge of #21318 - stepancheg:box-fns, r=alexcrichton
Functions are needed for safety and convenience. It is a common pattern to use `mem::transmute` to convert between `Box` and raw pointer, like this: ``` let b = Box::new(3); let p = mem::transmute(b); // pass `p` to some C library ``` After this commit, conversion can be written as: ``` let p = b.into_raw(); ``` `into_raw` and `from_raw` functions are still unsafe, but they are much safer than `mem::transmute`, because *raw functions do not convert between incompatible pointers. For example, this likely incorrect code can be successfully compiled: ``` let p: *mut u64 = ... let b: Box<u32> = mem::transmute(p); ``` Using `from_raw` results in compile-time error: ``` let p: *mut u64 = ... let b: Box<u32> = Box::from_raw(p); // compile-time error ``` `into_raw` and `from_raw` functions are similar to C++ `std::unique_ptr` `release` function [1] and constructor from pointer [2]. [1] http://en.cppreference.com/w/cpp/memory/unique_ptr/release [2] http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr
This commit is contained in:
commit
ca4b9674c2
2 changed files with 88 additions and 0 deletions
|
|
@ -102,6 +102,52 @@ impl<T> Box<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T : ?Sized> Box<T> {
|
||||
/// Constructs a box from the raw pointer.
|
||||
///
|
||||
/// After this function call, pointer is owned by resulting box.
|
||||
/// In particular, it means that `Box` destructor calls destructor
|
||||
/// of `T` and releases memory. Since the way `Box` allocates and
|
||||
/// releases memory is unspecified, so the only valid pointer to
|
||||
/// pass to this function is the one taken from another `Box` with
|
||||
/// `box::into_raw` function.
|
||||
///
|
||||
/// Function is unsafe, because improper use of this function may
|
||||
/// lead to memory problems like double-free, for example if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "may be renamed or moved out of Box scope")]
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
mem::transmute(raw)
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `Box`, returning the wrapped raw pointer.
|
||||
///
|
||||
/// After call to this function, caller is responsible for the memory
|
||||
/// previously managed by `Box`, in particular caller should properly
|
||||
/// destroy `T` and release memory. The proper way to do it is to
|
||||
/// convert pointer back to `Box` with `Box::from_raw` function, because
|
||||
/// `Box` does not specify, how memory is allocated.
|
||||
///
|
||||
/// Function is unsafe, because result of this function is no longer
|
||||
/// automatically managed that may lead to memory or other resource
|
||||
/// leak.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use std::boxed;
|
||||
///
|
||||
/// let seventeen = Box::new(17u32);
|
||||
/// let raw = unsafe { boxed::into_raw(seventeen) };
|
||||
/// let boxed_again = unsafe { Box::from_raw(raw) };
|
||||
/// ```
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "may be renamed")]
|
||||
pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
|
||||
mem::transmute(b)
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Box<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use core::ops::Deref;
|
|||
use core::result::Result::{Ok, Err};
|
||||
use core::clone::Clone;
|
||||
|
||||
use std::boxed;
|
||||
use std::boxed::Box;
|
||||
use std::boxed::BoxAny;
|
||||
|
||||
|
|
@ -73,3 +74,44 @@ fn deref() {
|
|||
fn homura<T: Deref<Target=i32>>(_: T) { }
|
||||
homura(Box::new(765i32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raw_sized() {
|
||||
unsafe {
|
||||
let x = Box::new(17i32);
|
||||
let p = boxed::into_raw(x);
|
||||
assert_eq!(17, *p);
|
||||
*p = 19;
|
||||
let y = Box::from_raw(p);
|
||||
assert_eq!(19, *y);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raw_trait() {
|
||||
trait Foo {
|
||||
fn get(&self) -> u32;
|
||||
fn set(&mut self, value: u32);
|
||||
}
|
||||
|
||||
struct Bar(u32);
|
||||
|
||||
impl Foo for Bar {
|
||||
fn get(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn set(&mut self, value: u32) {
|
||||
self.0 = value;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let x: Box<Foo> = Box::new(Bar(17));
|
||||
let p = boxed::into_raw(x);
|
||||
assert_eq!(17, (*p).get());
|
||||
(*p).set(19);
|
||||
let y: Box<Foo> = Box::from_raw(p);
|
||||
assert_eq!(19, y.get());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue