Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 96814ae

Browse files
committedMar 10, 2025
Rewrite example to not deal with Copy at all.
It also now demonstrates how to avoid memory leaks.
1 parent 2cc999d commit 96814ae

File tree

1 file changed

+19
-17
lines changed

1 file changed

+19
-17
lines changed
 

‎library/core/src/clone.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
327327
///
328328
/// #[derive(PartialEq)]
329329
/// struct MyDst<T: ?Sized> {
330-
/// flag: bool,
330+
/// label: String,
331331
/// contents: T,
332332
/// }
333333
///
@@ -343,32 +343,34 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
343343
/// (&raw const self.contents).byte_offset_from_unsigned(self)
344344
/// };
345345
///
346-
/// // Clone each field of `self` into `dest`.
347-
/// //
348-
/// // Since `flag` is `Sized`, we could also clone it as
349-
/// // dest.add(offset_of!(Self, flag)).cast::<bool>().write(self.flag.clone());
350-
/// // Since it is `Copy` (and therefore does not have a destructor), we could even write
351-
/// // *dest.add(offset_of!(Self, flag)) = self.flag;
352-
/// // but that must not be used for types with destructors, since it would read the place
353-
/// // in order to drop the old value. We have chosen to do neither of those, to demonstrate
354-
/// // the most general pattern.
355-
/// //
356-
/// // SAFETY: The caller must provide a `dest` such that these offsets are valid
346+
/// // Clone the *sized* fields of `self` (just one, in this example).
347+
/// // (By cloning this first and storing it temporarily in a local variable, we avoid
348+
/// // leaking it in case of any panic, using the ordinary automatic cleanup of local
349+
/// // variables. Such a leak would be sound, but undesirable.)
350+
/// let label = self.label.clone();
351+
///
352+
/// // SAFETY: The caller must provide a `dest` such that these field offsets are valid
357353
/// // to write to.
358354
/// unsafe {
359-
/// self.flag.clone_to_uninit(dest.add(offset_of!(Self, flag)));
355+
/// // Clone the unsized field directly from `self` to `dest`.
360356
/// self.contents.clone_to_uninit(dest.add(offset_of_contents));
361-
/// }
362357
///
363-
/// // All fields of the struct have been initialized, therefore the struct is initialized,
358+
/// // Now write all the sized fields.
359+
/// //
360+
/// // Note that we only do this once all of the clone() and clone_to_uninit() calls
361+
/// // have completed, and therefore we know that there are no more possible panics;
362+
/// // this ensures no memory leaks in case of panic.
363+
/// dest.add(offset_of!(Self, label)).cast::<String>().write(label);
364+
/// }
365+
/// // All fields of the struct have been initialized; therefore, the struct is initialized,
364366
/// // and we have satisfied our `unsafe impl CloneToUninit` obligations.
365367
/// }
366368
/// }
367369
///
368370
/// fn main() {
369371
/// // Construct MyDst<[u8; 4]>, then coerce to MyDst<[u8]>.
370372
/// let first: Rc<MyDst<[u8]>> = Rc::new(MyDst {
371-
/// flag: true,
373+
/// label: String::from("hello"),
372374
/// contents: [1, 2, 3, 4],
373375
/// });
374376
///
@@ -380,7 +382,7 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
380382
///
381383
/// assert_eq!(first.contents, [1, 2, 3, 4]);
382384
/// assert_eq!(second.contents, [10, 20, 30, 40]);
383-
/// assert_eq!(second.flag, true);
385+
/// assert_eq!(second.label, "hello");
384386
/// }
385387
/// ```
386388
///

0 commit comments

Comments
 (0)
Failed to load comments.