C++ Copy Constructors
A copy constructor is a constructor that builds a new object as a copy of an existing one. It runs when an object is made from another object of the same class.
The default copy shares the value
ScoreBox holds a pointer to an int. The class writes no copy constructor, so the copy holds the same pointer, and a change through one object shows in the other.
#include <iostream>
class ScoreBox {
public:
int* value;
ScoreBox(int v) {
value = new int(v);
}
};
int main() {
ScoreBox a(10);
ScoreBox b = a;
*b.value = 99;
std::cout << "A: " << *a.value << std::endl;
std::cout << "B: " << *b.value << std::endl;
return 0;
}A written copy constructor allocates its own
The written copy constructor allocates a fresh int for the new object. A change through one object now leaves the other alone, and each destructor frees its own int.
#include <iostream>
class ScoreBox {
public:
int* value;
ScoreBox(int v) {
value = new int(v);
}
ScoreBox(const ScoreBox& other) {
value = new int(*other.value);
}
~ScoreBox() {
delete value;
}
};
int main() {
ScoreBox a(10);
ScoreBox b = a;
*b.value = 99;
std::cout << "A: " << *a.value << std::endl;
std::cout << "B: " << *b.value << std::endl;
return 0;
}Assignment is a separate path
A static counter inside the copy constructor counts copies. The counter is shared by every object, so one copy construction raises it to 1, and the assignment after it leaves it at 1.
#include <iostream>
class ScoreBox {
public:
static int copies;
int* value;
ScoreBox(int v) {
value = new int(v);
}
ScoreBox(const ScoreBox& other) {
copies++;
value = new int(*other.value);
}
};
int ScoreBox::copies = 0;
int main() {
ScoreBox a(10);
ScoreBox b = a;
ScoreBox c(30);
c = a;
std::cout << "Copies: " << ScoreBox::copies << std::endl;
std::cout << "B: " << *b.value << std::endl;
std::cout << "C: " << *c.value << std::endl;
return 0;
}Example
#include <iostream>
class ScoreBox {
public:
int* value;
ScoreBox(int v) {
value = new int(v);
}
ScoreBox(const ScoreBox& other) {
value = new int(*other.value);
}
~ScoreBox() {
delete value;
}
};
int main() {
ScoreBox a(50);
ScoreBox backup = a;
*a.value = 80;
std::cout << "A: " << *a.value << std::endl;
std::cout << "Backup: " << *backup.value << std::endl;
return 0;
}Key points
- A copy constructor takes one parameter, a reference to an object of the same class.
- A class that writes no copy constructor gets one from the compiler.
- The supplied copy constructor copies each member exactly as it is.
- A copied pointer member points at the same value as the original pointer.
- A written copy constructor can allocate fresh storage for the new object.
- Assignment between two ready objects is a separate path and does not run the copy constructor.
In this example, the copy constructor gives backup its own int with the value 50. The next line raises the value inside a to 80. The backup still prints 50, because its storage is separate.
Note
The counter member is marked static, so every object shares the one counter instead of each object holding its own. Static members get their full lesson at the end of this category.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A class holds a raw pointer member and writes no copy constructor. What does a copy of an object share?