Your question is the wrong question.
First, C++ default copy/assign is memberwise; it recursively copies/assigns based on what the members do.
Well designed C++ types follow a few patterns in what they do when copied/assigned that lines up with 3 different kinds of primitive types; value, reference and pointer semantics.
A value semantics type behaves like a value. This corresponds to your "deep copy" roughly. Modifying one variable that follows value semantics never changes another. std::vector
is a value semantics type, as is int
, double
, std::string
and other std
container types. Value semantics are a strong pattern, and make reasoning about program behaviour easy. Note that value semantics need not be implemented as values; vector is typically implemented as a triple of pointers, with construction/copying/etc overloaded; but to the user of a vector variable, it is a value. (The small exception is move construction (and swap), where vector guarantees the moved-to vector steals the contents; iterators remain valid but refer to a different vector afterwards)
A reference semantics type behaves like a C++ reference type -- int&
. This is not the same as a Java/C# reference. C++ references are aliases; int& a=b;
means a
is another name for b
. Then a=7
makes both a
and b
equal 7
. If you had another reference c
, a=c
would not rebind a
to refer to c
; it would change what a
referred to to have the same value as what c
referred to. Reference semantics is very confusing because Ref a = b;
and a = b;
do fundamentally different things.
Complex objects with reference semantics are rare.
A pointer semantics is like reference semantics, but assignment rebinds who it points to. Sometimes an additional operation, like &
, is needed to create a new pointer. A type with pointer semantics includes std::reference_wrapper
, std::string_view
, std::shared_ptr<double>
, gsl::span<char>
and int*
.
Typically it is a bad idea to mix members with different semantics in the same type; the rule of 0/3/5 states that the best move/copy/assogn/ctor/dtor is the empty one. Your resource management types use RAII and write those special members, the other types aggregate them. Value semantics types are not used mixed with reference/pointer in order for the composite class to get coherant semantics.
TL;DR: it depends. Read the documentation on your members. Document what semantics your types have so users know what to expect.
Note, however, that reference semantics is incompatible with being stored in a std container.
{1,2,3}
is being stored inv1
is required to provide a complete answer. – Nuzzle