The problem is that if you later modify Foo
, you will run into problems and the compiler won't warn you about it:
struct Foo {
_s: String,
}
fn main() {
let k = Foo { _s: "Hello".to_string() };
let ref l = k;
let _m = unsafe {core::ptr::read(l)};
}
(Playground)
Errors:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.72s
Running `target/debug/playground`
free(): double free detected in tcache 2
timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11: 8 Aborted timeout --signal=KILL ${timeout} "$@"
To avoid this problem, you can do the following:
#[derive(Clone, Copy)] // SAFETY: `Foo` must be able to implement `Copy` due to `core::ptr::read(l)` in `main`
struct Foo {
_s: String,
}
This then would give you a compiler error:
Compiling playground v0.0.1 (/playground)
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:1:17
|
1 | #[derive(Clone, Copy)]
| ^^^^
2 | struct Foo {
3 | _s: String,
| ---------- this field does not implement `Copy`
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0204`.
error: could not compile `playground` due to previous error
(Playground)
But if you add Copy
in the original example …
#[derive(Clone, Copy)]
struct Foo;
… then you don't need core::ptr::read(l)
at all:
fn main() {
let k = Foo;
let ref l = k;
let _m = *l;
}
(Playground)
So using core::ptr::read(l)
is pretty much useless here. If it's safe sound to use and if you thus could add #[derive(Copy)]
then you don't wouldn't need it. If you don't add #[derive(Copy)]
, then you might later cause undefined behavior at runtime because you make some changes without noticing that these cause core::ptr::read(l)
to result in undefined behavior.