Default Copy Behavior
Objects can be copied by default, and this holds for user-defined types and builtin types alike.
Copies You Get Without Asking
When you create a new object from an existing one in C++, you usually do not have to write any special instructions telling the language how to do the copying. Objects can be copied by default. This holds for objects of types you define yourself, and it also holds for builtin types such as int and double.
This article answers a precise question: what, exactly, does that default copy do? The short answer is that the default copy works member by member. Each piece of data that makes up an object is transferred from the source to the new object, one piece at a time. Once you see that pattern, the behavior of many everyday C++ statements becomes predictable.
Objects as Labeled Compartments
A member is one of the named pieces of data inside an object. A useful way to picture an object is as a small container with labeled compartments. Each compartment holds one value. The copy operation works through the compartments in turn, moving the value in each one into the matching compartment of the new object.
This is the idea behind the name memberwise copy. The copy is organized around members and is applied to each of them. Nothing about this requires the object to be large or unusual. Even an object with only two members is copied by handling each of those two members.
Read the diagram from left to right. The source object on the left still holds its own members. The target object on the right has its own members, and each one is filled from the matching member of the source. The result is two separate objects that hold equal member values. The source does not describe any further link between the two objects after the copy, so you should not assume one.
Tracing a Pair Through Initialization and Assignment
The following example is an original illustration rather than the source's own code. It uses a small user-defined type called Pair with two int members, so you can follow each member through the copy. Before reading the output, try to predict what each printed line will show.
What do you think happens?
Pair a is set to {3, 7}. Pair b is initialized from a, and Pair c is then assigned from a. What does each of the three printed lines show?
Reveal answer
All three lines show 3 and 7
Initialization copies a's members into b as b is created, and assignment copies a's members into the existing c, overwriting c's 0 and 0. Each step performs a memberwise copy, so all three objects end up with the same member values.
3 7
3 7
3 7- Pair is a user-defined type with two members, first and second
- Pair b = a copies each member of a into the new object b during initialization
- c = a copies each member of a into the existing object c during assignment
- Each printed line shows the two member values of one object
Notice that the source in this example is never changed by either copy. The line Pair b = a leaves a with 3 and 7, and the line c = a leaves a with 3 and 7 as well. The copy moves values out of the source and into the target, and the source keeps its own member values.
Initialization and Assignment Compared
C++ uses two operations that make use of the default copy. The first is initialization, in which a new object is created and given the values of an existing object at the moment it comes into existence. In the example above, b is created this way. The second is assignment, in which an object that already exists is overwritten with the values of another object. The c in the example is updated this way, even though it had values before the assignment.
The two operations differ in when the target comes into existence, but they share the same core action. The source is explicit that both perform a memberwise copy, so they transfer the same member values. This is why the three variables in the example end up holding the same value even though only one of them was set up by initialization.
Does the Type Matter?
A natural question is whether the default copy behaves differently for types you write yourself and for types the language provides. The source says it does not. Objects can be copied by default for user-defined types, and this is also true for builtin types. The default meaning of copy is the same memberwise copy in both cases.
5 9- int y = x copies the value of the builtin int x into the new object y
- y = 9 overwrites only y; x keeps its own value
Mistakes Learners Make
Common mistake Thinking a copy happens only for simple builtin values
What it looks likeAssuming Pair b = a needs special code because Pair is a type you wrote yourself
Why it failsThe source says objects can be copied by default for user-defined types as well as builtin types
Do this insteadExpect the default memberwise copy for your own types unless you have been told otherwise
Common mistake Believing initialization and assignment copy different things
What it looks likeThinking b = a copies everything while c = a copies only one member
Why it failsThe source states that both initialization and assignment perform a memberwise copy and transfer the same member values
Do this insteadTreat both as a member-by-member transfer and check each member when you trace the result
Common mistake Assuming that copied objects stay linked after the copy
What it looks likeExpecting a change to b to alter a after the copy
Why it failsThe source describes two separate objects holding equal member values and does not describe any link between them after the copy
Do this insteadTrace each object separately, using the member values each one holds
Common mistake Forgetting that the source object is not changed by a copy into a new object
Practice: Trace the Members
Using the Pair example, suppose you add the line b.first = 10; after Pair b = a; but before the assignment to c. Trace each of the three objects and state the values of first and second in a, b, and c at the point where c = a runs. Then say what the final output looks like for the first line.
Hints
- Start by writing down the member values of a, which are never changed in this change
- Remember that b.first = 10 changes one compartment of b only
- Assignment c = a copies the members of a into c, overwriting whatever c held
Key Takeaways on Default Copying
- 1Objects can be copied by default, for user-defined types and for builtin types alike
- 2The default copy is memberwise: each member of the source is copied into the corresponding member of the target
- 3Initialization and assignment both perform a memberwise copy and transfer the same member values
- 4After a default copy the source and target hold equal member values, and the source does not describe any link between them
At a glance
- Objects can be copied by default, and this holds for user-defined types and builtin types alike
- The default copy is memberwise: each member of the source is transferred into the matching member of the target
- Initialization and assignment both perform a memberwise copy, so they transfer the same member values
- After a default copy, the source and target hold equal member values, and the source does not describe any link between them