diff options
| author | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-10-15 16:32:14 +0100 |
|---|---|---|
| committer | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-11-05 00:50:41 +0000 |
| commit | 651cf58f2e906fa6d333013891adca5074440bea (patch) | |
| tree | 0a9de6025b1d0605d854beb2cbfbda06fb91c4d2 /src/liballoc/arc.rs | |
| parent | d34318dd538bf4c9175e4138b3e4188ea8211620 (diff) | |
| download | rust-651cf58f2e906fa6d333013891adca5074440bea.tar.gz rust-651cf58f2e906fa6d333013891adca5074440bea.zip | |
Add `{into,from}_raw` to Rc and Arc
Diffstat (limited to 'src/liballoc/arc.rs')
| -rw-r--r-- | src/liballoc/arc.rs | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7a07e007ce1..5db5a315f4a 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -270,6 +270,68 @@ impl<T> Arc<T> { Ok(elem) } } + + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Arc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub fn into_raw(this: Self) -> *mut T { + let ptr = unsafe { &mut (**this.ptr).data as *mut _ }; + mem::forget(this); + ptr + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Arc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Arc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the + // `data` field from the pointer. + Arc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(ArcInner<T>, data)) as *mut _) } + } } impl<T: ?Sized> Arc<T> { @@ -1180,6 +1242,23 @@ mod tests { } #[test] + fn into_from_raw() { + let x = Arc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + + #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); let mut cow1 = cow0.clone(); |
