Theme
Q022. Why can a type that implements Drop not implement Copy?
Short Answer
Rust forbids combining Copy with Drop because Copy permits implicit duplication without running custom code, while Drop represents type-specific cleanup. If both were allowed, ordinary reads could silently create additional values that later run the destructor, making unique cleanup responsibilities unsafe or ambiguous. Use moves for unique ownership or an explicit Clone with defined duplication semantics.
Deep Dive
Drop means destruction has observable, type-specific behavior: releasing memory, closing a handle, unlocking a resource, or maintaining another invariant. Copy means the compiler may duplicate the value implicitly without calling a hook.
Those contracts conflict. A bitwise duplicate of an owning pointer would not allocate another resource or update shared metadata, yet both resulting values would appear entitled to run Drop. Rust therefore rejects Copy for any type implementing Drop, and structural Copy eligibility prevents containing such a value in another Copy type.
Not every hypothetical destructor would make copying unsound, but the language rule keeps Copy values free of custom destruction and makes implicit duplication predictable. If duplication is valid, Clone can explicitly perform the required allocation, handle duplication, or reference-count update.
Internal Model
The compiler reports error E0184 when a type attempts to implement both traits. This is checked from the type definition; no runtime owner count is introduced to reconcile the conflict.
Moves remain compatible with Drop because a move preserves one cleanup path. The moved-from place is not dropped, and the destination eventually runs the destructor.
Example
rust
#[derive(Clone)]
struct Buffer(Vec<u8>);
impl Drop for Buffer {
fn drop(&mut self) {
println!("release {} bytes", self.0.len());
}
}
fn main() {
let first = Buffer(vec![1, 2, 3]);
let second = first.clone();
println!("{} {}", first.0.len(), second.0.len());
// Adding `Copy` to the derive list would be rejected with E0184.
}Common Mistakes
- Saying Rust could safely call
Clonewhenever aCopyoccurs. - Assuming a moved value and a copied value create the same number of destructor calls.
- Using a raw
Copyhandle while still treating every copy as an automatic unique owner.
Follow-ups
- Why can
Clonecoexist withDrop? - How does moving preserve exactly one destructor path?
- Why is a raw file descriptor
Copywhile an owning file handle is not?
Related
- Q005. What does it mean for a value to own a resource?
- Q013. What happens to the source binding after a move?
- Q021. When can a type implement
Copy?
References
- The Rust Programming Language
- Rust Reference
- Rust Standard Library