Skip to content

Commit 5a722f8

Browse files
committed
box: into_raw, from_raw functions
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 = boxed::into_raw(b); ``` `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
1 parent 0ab8d5d commit 5a722f8

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/liballoc/boxed.rs

+46
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,52 @@ impl<T> Box<T> {
102102
}
103103
}
104104

105+
impl<T : ?Sized> Box<T> {
106+
/// Constructs a box from the raw pointer.
107+
///
108+
/// After this function call, pointer is owned by resulting box.
109+
/// In particular, it means that `Box` destructor calls destructor
110+
/// of `T` and releases memory. Since the way `Box` allocates and
111+
/// releases memory is unspecified, so the only valid pointer to
112+
/// pass to this function is the one taken from another `Box` with
113+
/// `box::into_raw` function.
114+
///
115+
/// Function is unsafe, because improper use of this function may
116+
/// lead to memory problems like double-free, for example if the
117+
/// function is called twice on the same raw pointer.
118+
#[unstable(feature = "alloc",
119+
reason = "may be renamed or moved out of Box scope")]
120+
pub unsafe fn from_raw(raw: *mut T) -> Self {
121+
mem::transmute(raw)
122+
}
123+
}
124+
125+
/// Consumes the `Box`, returning the wrapped raw pointer.
126+
///
127+
/// After call to this function, caller is responsible for the memory
128+
/// previously managed by `Box`, in particular caller should properly
129+
/// destroy `T` and release memory. The proper way to do it is to
130+
/// convert pointer back to `Box` with `Box::from_raw` function, because
131+
/// `Box` does not specify, how memory is allocated.
132+
///
133+
/// Function is unsafe, because result of this function is no longer
134+
/// automatically managed that may lead to memory or other resource
135+
/// leak.
136+
///
137+
/// # Example
138+
/// ```
139+
/// use std::boxed;
140+
///
141+
/// let seventeen = Box::new(17u32);
142+
/// let raw = unsafe { boxed::into_raw(seventeen) };
143+
/// let boxed_again = unsafe { Box::from_raw(raw) };
144+
/// ```
145+
#[unstable(feature = "alloc",
146+
reason = "may be renamed")]
147+
pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
148+
mem::transmute(b)
149+
}
150+
105151
#[stable(feature = "rust1", since = "1.0.0")]
106152
impl<T: Default> Default for Box<T> {
107153
#[stable(feature = "rust1", since = "1.0.0")]

src/liballoc/boxed_test.rs

+42
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use core::ops::Deref;
1515
use core::result::Result::{Ok, Err};
1616
use core::clone::Clone;
1717

18+
use std::boxed;
1819
use std::boxed::Box;
1920
use std::boxed::BoxAny;
2021

@@ -73,3 +74,44 @@ fn deref() {
7374
fn homura<T: Deref<Target=i32>>(_: T) { }
7475
homura(Box::new(765i32));
7576
}
77+
78+
#[test]
79+
fn raw_sized() {
80+
unsafe {
81+
let x = Box::new(17i32);
82+
let p = boxed::into_raw(x);
83+
assert_eq!(17, *p);
84+
*p = 19;
85+
let y = Box::from_raw(p);
86+
assert_eq!(19, *y);
87+
}
88+
}
89+
90+
#[test]
91+
fn raw_trait() {
92+
trait Foo {
93+
fn get(&self) -> u32;
94+
fn set(&mut self, value: u32);
95+
}
96+
97+
struct Bar(u32);
98+
99+
impl Foo for Bar {
100+
fn get(&self) -> u32 {
101+
self.0
102+
}
103+
104+
fn set(&mut self, value: u32) {
105+
self.0 = value;
106+
}
107+
}
108+
109+
unsafe {
110+
let x: Box<Foo> = Box::new(Bar(17));
111+
let p = boxed::into_raw(x);
112+
assert_eq!(17, (*p).get());
113+
(*p).set(19);
114+
let y: Box<Foo> = Box::from_raw(p);
115+
assert_eq!(19, y.get());
116+
}
117+
}

0 commit comments

Comments
 (0)