@@ -578,6 +578,62 @@ impl<T, A: Allocator> Box<T, A> {
578
578
{
579
579
* boxed
580
580
}
581
+
582
+ /// Safely reads the value on heap without deallocating.
583
+ ///
584
+ /// This method is mostly useful for avoiding reallocations.
585
+ /// The method consumes the box to prevent double-free.
586
+ /// The value on heap should be considered truly uninitialized and MUST NOT be read.
587
+ /// Specifically, this code is definitely UB:
588
+ ///
589
+ /// ```no_run
590
+ /// #![feature(new_uninit)]
591
+ ///
592
+ /// let value = Box::new("hello".to_owned());
593
+ /// // Double free here!
594
+ /// unsafe { Box::take(value).1.assume_init(); }
595
+ /// ```
596
+ ///
597
+ /// # Examples
598
+ ///
599
+ /// ```
600
+ /// #![feature(new_uninit)]
601
+ ///
602
+ /// let boxed_value = Box::new("hello".to_owned());
603
+ /// let (mut value, allocation) = Box::take(boxed_value);
604
+ /// assert_eq!(value, "hello");
605
+ /// // More realistic code would consume the value and produce other value.
606
+ /// // For simple demonstration we just modify it here.
607
+ /// value.push_str(" world");
608
+ /// let boxed_value = Box::write(allocation, value);
609
+ /// assert_eq!(*boxed_value, "hello world");
610
+ /// ```
611
+ #[ unstable( feature = "new_uninit" , issue = "63291" ) ]
612
+ #[ rustc_const_unstable( feature = "const_box" , issue = "92521" ) ]
613
+ #[ inline]
614
+ pub const fn take ( this : Self ) -> ( T , Box < mem:: MaybeUninit < T > , A > ) {
615
+ let ( raw, alloc) = Box :: into_raw_with_allocator ( this) ;
616
+ unsafe {
617
+ // SAFETY:
618
+ // * The pointer given to from_raw_in was obtained from box above using the same
619
+ // allocator
620
+ // * Casting `*mut T` to `*mut MaybeUninit<T>` is sound because they have same layout
621
+ // * Safely obtaining `&mut T` pointing into the allocation will become impossible after
622
+ // this call because we consume `this` (no variance issues)
623
+ // * `MaybeUninit` disables destructor of `T` so it can't double free
624
+ // * Leak shouldn't happen because `assume_init_read` below doesn't panic and the value
625
+ // can be dropped afterwards
626
+ let new_box = Box :: from_raw_in ( raw. cast :: < mem:: MaybeUninit < T > > ( ) , alloc) ;
627
+ // SAFETY:
628
+ // * The value being read was proven to be initialized when this function was called
629
+ // * We didn't touch the value inside this function, just cast the pointer, so it's
630
+ // still valid.
631
+ // * We don't read the value on heap again and prevent safe code from reading it by
632
+ // marking the box with `MaybeUninit`.
633
+ let value = new_box. assume_init_read ( ) ;
634
+ ( value, new_box)
635
+ }
636
+ }
581
637
}
582
638
583
639
impl < T > Box < [ T ] > {
0 commit comments