Object Lifetime and Destructors
Keeping track of which object owns the resource is what prevents leaks and double releases.
Why Every Transfer Needs a Decision
Every time a program passes a container to a function, returns one, or stores one in another variable, it has to decide what happens to the data inside. The container might be duplicated, so that two independent objects hold the same elements. Or its contents might be handed over to a new owner, so that the original no longer holds them. These two choices are the subject of copy and move semantics.
Read the next few sections with one question in mind: after this operation finishes, how many objects are responsible for the data, and what state is each one in? Almost every rule about copying, moving, and destroying objects is an answer to that question.
Copying a Container
Copying a container creates a second container that holds the same values as the first. Afterward the two containers are separate objects. Changing an element in one does not change the element in the other. Copying is the operation that produces this independent second object, and it is the default way to make a duplicate when no other choice has been made explicitly.
The important point is that both containers remain usable and independent. Each one is responsible for its own elements. Because the elements must be duplicated, a copy can take more time and memory than the original took to create, especially when the container is large.
Tracing a Copy Step by Step
Copying a three-element container
A container named scores holds the elements 90, 75, and 88. The program creates a second container named backup as a copy of scores, then changes the first element of backup to 60. What does scores hold afterward?
- 1Start with the original
scores owns its elements, and they are 90, 75, and 88.
- 2Make the copy
backup is created as a second container holding the same values, 90, 75, and 88. It is a separate object, and it is responsible for its own elements.
- 3Change one container
Setting the first element of backup to 60 changes only backup's element. The change happens in the copy's own storage.
- 4Check the original
scores still holds 90, 75, and 88, because the two containers never shared their elements.
scores still holds 90, 75, and 88. backup holds 60, 75, and 88. The copy and the original are independent.
Moving a Container
Moving a container transfers its contents to a new container instead of duplicating them. The destination takes over the data, and the source is left in a valid but unspecified state. A move is useful when the source is no longer needed, because the program avoids building a second copy of the elements. This is why a move can be cheaper than a copy: no elements need to be duplicated, because the existing data changes hands.
In C++ code, the move is requested by casting the source to an rvalue reference with std::move. This tells the language that the source may give up its contents.
What do you think happens?
After a move, what do you think the source container holds?
Reveal answer
A valid but unspecified state, so code should not depend on its contents
The source is left valid but unspecified. It is not guaranteed to be empty, and it is not guaranteed to keep its elements, so a program should not rely on what the source holds after the move.
Who Owns the Resource
A container usually owns a resource, such as a block of memory that holds its elements. Copy and move operations decide what happens to that resource. A copy must give the new object its own resource, so that two objects never release the same memory. A move hands the existing resource to the new object and leaves the source without it, so that only one object is responsible for it at any time.
Keeping track of which object owns the resource is what prevents leaks and double releases. A leak happens when a resource is never released. A double release happens when two objects both try to release the same resource. Copies avoid the second problem by creating new resources, and moves avoid it by transferring the single existing resource.
The Essential Operations Working Together
Copy and move behavior is controlled by a small group of special member functions. Together they describe how an object is created from another object, how an existing object is assigned from another, and how an object is cleaned up. The essential operations are the copy constructor, the copy assignment operator, the move constructor, the move assignment operator, and the destructor.
The constructors create a new object, while the assignment operators replace the value of one that already exists. A copy version takes a read-only reference to its source, and a move version takes a reference that allows the source to be emptied. The destructor is the step that releases what the object owns. Seeing these operations as a set makes it clear that copying and moving are two forms of the same job, producing a new value from an existing one, and that destruction is what ends the object's ownership.
Suppressing Copy or Move
Sometimes a class should not be copied or moved at all. A handle that represents a unique external resource, or an object whose identity matters, may be wrong to duplicate. Suppressing an operation means stating that the operation is not available, so that code which tries to use it fails to compile instead of silently producing an incorrect result. Choosing to allow or suppress an operation is a design decision about what the class means.
| Suppressed operation | What is blocked | What remains available | Why a designer might choose it |
|---|---|---|---|
| Copy operations | Creating an independent duplicate and copy assignment | Move operations, when the class provides them | The object represents a unique resource that should not be duplicated, but its ownership can be handed to a new owner |
| Move operations | Transferring contents to a new object or value | Copy operations, when the class provides them | Moving would give up the object's contents in a way that breaks its meaning, while duplicating it is still acceptable |
| Both copy and move | Duplicating and transferring the object | Creating the object and cleaning it up with the destructor | The object's identity matters, so it should only be created and then used where it lives |
Which operations remain available when a class suppresses copying or moving
Mistakes Learners Make with Copies and Moves
Common mistake Assuming a moved-from source still holds its original elements
What it looks likeAfter moving scores into another container, the code reads scores and expects 90, 75, and 88.
Why it failsThe source is left in a valid but unspecified state, so its contents are not something the program can rely on after the move.
Do this insteadUse the destination after a move, and only reassign or destroy the source.
Common mistake Copying a large container when the source is no longer needed
What it looks likeA function returns a large container built inside it, and the caller duplicates it again instead of handing it over.
Why it failsA copy must duplicate every element, which can take more time and memory than the original took to create.
Do this insteadWhen the source will not be used again, a move hands the existing resource to the new owner instead of building a second copy.
Common mistake Treating copy and move as the same operation
Why it failsA copy leaves two objects that each own their own resource, while a move leaves only one object responsible for the resource.
Practice Tracing Ownership
A container named readings owns the elements 4, 8, and 15. A program first copies readings into a container named archive, then moves readings into a container named latest. For each of the three containers (readings, archive, latest), say whether it owns a resource holding elements after the moves, and say what its state is. Explain your answer in terms of copies creating new resources and moves transferring existing ones.
Hints
- Start by drawing who owns a resource after the copy, before you consider the move.
- After the move, the source is valid but unspecified, so do not claim it still holds 4, 8, and 15.
- Count how many objects own a resource holding the elements after each step.
Key Takeaways
- A copy produces a second, independent container holding the same values, and each container owns its own resource.
- A move transfers the existing resource to a new owner and leaves the source valid but unspecified, which makes it cheaper than a copy when the source is no longer needed.
- The copy constructor, copy assignment, move constructor, move assignment, and destructor together control how objects are created, replaced, and released.
- A class can suppress copy or move operations to state that they are not available, so misuse fails at compile time when the object's meaning forbids duplication or transfer.