Deep Copy VS Shallow Copy in C++
- Shallow Copy is Used by Default Copy Constructor in C++
- Use Custom Copy Constructor to Implement Deep Copy Behavior in C++
This article will demonstrate multiple methods about how to use deep copy VS shallow copy in C++.
Shallow Copy is Used by Default Copy Constructor in C++
C++ classes are generally defined with several operations, collectively referred to as copy control
, specified explicitly by the user or implicitly by the compiler. These member functions are denoted as: copy constructor
, copy-assignment operator
, move constructor
, move-assignment operator
, and destructor
. Copy constructor and move constructor implement operations that happen when the object is initialized from another object of the same type. Although, when these functions are synthesized by the compiler implicitly, some class types may behave incorrectly. E.g., the classes that manage dynamic memory will share data members that need to be allocated manually. Thus the programmer is responsible for implementing the above member functions explicitly.
In this case, we demonstrate the case of a copy constructor in a class named Person
with two std::string
data members, one of which is allocated using the new
operator. The following example code shows what happens when the copy constructor is not defined explicitly, and we initialize a Person
object with another Person
object. Notice that P1
has stored strings - Buddy
/Rich
after initialization and P2
has the same values after copy constructor is called in the statement - Person P2 = P1;
. After the renamePerson
function is executed on the P1
object, the surname
data member of the P2
object is also modified.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
class Person {
public:
Person() = default;
Person(string n, string s) {
name = std::move(n);
surname = new string(std::move(s));
}
~Person() { delete surname; }
void renamePerson(const string &n, const string &s) {
name.assign(n);
surname->assign(s);
};
string &getName() { return name; };
string &getSurname() { return *surname; };
void printPerson() { cout << name << " " << *surname; }
private:
string name;
string *surname{};
};
int main() {
Person P1("Buddy", "Rich");
Person P2 = P1;
P1.printPerson();
cout << endl;
P2.printPerson();
cout << endl;
P1.renamePerson("Heinz", "Lulu");
P1.printPerson();
cout << endl;
P2.printPerson();
cout << endl;
exit(EXIT_SUCCESS);
}
Output:
Buddy Rich
Buddy Rich
Heinz Lulu
Buddy Lulu
Use Custom Copy Constructor to Implement Deep Copy Behavior in C++
On the other hand, when we implement a custom copy constructor for the Person
class, it behaves correctly and does not modify the P2
object after the P1.renamePerson("Heinz", "Lulu")
statement. In the previous code snippet, surname
member of P2
object pointed to the same string as the P1
object, and renamePerson
modified both objects. This time, P2
has its own surname
member allocated on dynamic memory and does not share it with the P1
object.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
class Person {
public:
Person() = default;
Person(string n, string s) {
name = std::move(n);
surname = new string(std::move(s));
}
Person(Person &p) {
name = p.name;
surname = new string(*p.surname);
}
~Person() { delete surname; }
void renamePerson(const string &n, const string &s) {
name.assign(n);
surname->assign(s);
};
string &getName() { return name; };
string &getSurname() { return *surname; };
void printPerson() { cout << name << " " << *surname; }
private:
string name;
string *surname{};
};
int main() {
Person P1("Buddy", "Rich");
Person P2 = P1;
P1.printPerson();
cout << endl;
P2.printPerson();
cout << endl;
P1.renamePerson("Heinz", "Lulu");
P1.printPerson();
cout << endl;
P2.printPerson();
cout << endl;
exit(EXIT_SUCCESS);
}
Output:
Buddy Rich
Buddy Rich
Heinz Lulu
Buddy Rich
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook