Skip to content

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 Clone whenever a Copy occurs.
  • Assuming a moved value and a copied value create the same number of destructor calls.
  • Using a raw Copy handle while still treating every copy as an automatic unique owner.

Follow-ups

  • Why can Clone coexist with Drop?
  • How does moving preserve exactly one destructor path?
  • Why is a raw file descriptor Copy while an owning file handle is not?

References

  • The Rust Programming Language
  • Rust Reference
  • Rust Standard Library