I got so worried about accidentally deep-copying stuff that I ended up with an ugly C++ hack:
C(const C &) = delete;
C &operator=(const C &) = delete;
C(C &&) noexcept = default;
C &operator=(C &&) noexcept = default;
struct MakeCopy {
const C &src;
MakeCopy(const C &src) : src(src) { }
};
MakeCopy make_copy() const { return *this; }
C(MakeCopy src) : field1(src.src.field1), (blah blah) { }
Then, when you really want to copy stuff, you have to say "a = b.make_copy();".
This isn't really clean, because it's too easy to add a field to C and then forget to add it to the "manual copy constructor", but so far I found it good enough for me.
In Rust, if you want a deep copy you (IIRC) implement the Clone trait, which allows you to explicitly clone everything. Many collections in the standard library already implement this, so you get it by default :).
Edit: I should point out that deep copies can only be explicit in Rust -- there's no implicit deep copy AFAIK.
There is no implicit deep copy, Clone is usually how a deep copy is implemented, but not all Clones are deep copies. Rc, for example, bumps a reference count on Clone.
This isn't really clean, because it's too easy to add a field to C and then forget to add it to the "manual copy constructor", but so far I found it good enough for me.