Shallow Copy in C++
In this article, we will discuss the shallow copy in C++ with examples.
What is a shallow copy?
In C++, a shallow copy is a sort of copy operation that copies the values of the basic data members to generate a new object with the same contents as the original object. A shallow copy implies that it will point to the same memory addresses as the original object, mainly when it includes pointers to dynamically allocated memory.
Understanding shallow copy:
Programmers should be aware of shallow copies, as improper usage may lead to unexpected behaviour. For instance, if two objects share dynamically allocated memory, and one edits the memory, both will reflect the changes.
Example:
Let's take an example to understand the use of shallow copy in C++:
#include <iostream>
class MyClass {
public:
int value1;
int* value2;
MyClass(int val1, int* val2) {
this->value1 = val1;
this->value2 = new int(*val2);
}
MyClass(const MyClass& other) {
this->value1 = other.value1;
this->value2 = new int(*(other.value2));
}
~MyClass() {
delete value2;
}
};
int main() {
MyClass obj1(10, new int(20));
MyClass obj2(obj1);
*obj1.value2 = 30;
std::cout << *obj2.value2 << std::endl;
return 0;
}
Output:
![Shallow Copy in C++](https://static.tutorialandexample.com/cpp/shallow-copy-in-cpp1.png)
Explanation:
The preceding example creates a fresh instance of the MyClass class named obj1. After that, we copy obj1 shallowly and assign it to the value of obj2. As a result, the int variable's dynamically created memory will now be shared by objects obj1 and obj2, respectively.
After that, we change the value of obj1.y. The actual value of obj2.y will likewise change because obj1 and obj2 use the same memory address for y.
Deep copy vs shallow copy:
Key variations
When performing a deep copy, the old object's values, including any dynamically created memory, are carried over to the new object. A shallow copy of an object just duplicates its primitive data members' values.
It means that the deep copy will make fresh copies of any dynamically allocated memory that the original object contains pointers to and assign those pointers to the new object. The original object and the shallow copy will both point to the same dynamically created memory because the shallow copy will only copy the pointers' values.
Situations where it is inappropriate to use shallow copy:
When duplicating an object that contains any pointers to dynamically allocated memory, a shallow copy is not appropriate. When an object containing pointers to dynamically allocated memory is copied using a shallow copy, both the original object and the shallow copy will point to the same memory. It may cause our program to contain faults and issues like memory leaks and dangling pointers.
Shallow Copy Pitfalls:
A copy operation known as a shallow copy merely copies the values of the primitive data members, creating a new object with the same values as the original object. It means that any pointers to dynamically allocated memory that are present in the original object will be carried over by the shallow copy.
It may result in a variety of potential issues and bugs, such as:
Memory leaks: The dynamically allocated memory that the shallow copy references to will be erased instead of being deleted when it exits its scope. It may result in a memory leak, in which memory is created even when it is no longer being used by any object.
Dangerous pointers: The shallow copy continues to point to the same memory locations if the original object is changed or removed after it has been made. Dangling pointers, or pointers that point to previously removed memory, might result from this. Dangerous behaviour and crashes are just two examples of the issues that might result from dangling pointers.
Data corruption: If two objects share dynamically allocated memory and one of the objects makes modifications to the memory, the changes are mirrored in the other object(s) as well. Data corruption, where the data in both objects is wrong, might result from this.
Example:
A shallow copy memory leak is demonstrated in the code below:
#include <iostream>
class MyClass {
public:
int x;
int* y;
MyClass(int x, int* y) {
this->x = x;
this->y = y;
}
MyClass(const MyClass& other) {
this->x = other.x;
this->y = other.y;
}
};
int main() {
MyClass obj1(10, new int(20));
MyClass obj2(obj1);
delete obj1.y;
*obj2.y = 30;
return 0;
}
Output:
![Shallow Copy in C++](https://static.tutorialandexample.com/cpp/shallow-copy-in-cpp2.png)
Avoiding the dangers of shallow copy:
Use deep copy rather than shallow copy to avoid the problems as much as possible. A deep copy operation produces a new object with exactly the identical values as the original object, including any dynamically allocated memory, as the original object.
Avoiding the dangers of shallow copy means that the deep copy will make fresh copies of any dynamically allocated memory to which the original object contains pointers and assign those pointers to the new object. It eliminates any possibility of memory leaks, dangling pointers, or data corruption, and guarantees that the two objects are independent.
Being cautious when using shallow copy is another approach to avoiding its hazards. If we must utilize shallow copy, understand the hazards and take precautions to reduce them. For instance, remove any dynamically allocated RAM that is no longer needed.
Use of dynamic memory allocation:
Heap memory is commonly called dynamic memory allocation. It is a type of memory that can be allocated and released at runtime. As a result, we can allocate as much or as little RAM as you require and deallocate it once you are done.
A copy operation known as a shallow copy merely copies the values of the primitive data members, creating a new object with identical values to the original object. Dynamic memory allocation implies that the shallow copy will point to the same memory addresses as the original object if it contains any pointers to dynamically generated memory.
Dynamic memory allocation could be troublesome if the original object is changed or removed after the shallow copy has been made. For instance, if dynamically allocated memory for the original object is removed, the shallow copy's pointer will become a dangling pointer. Dangerous behaviour and crashes are two examples of the issues that might result from dangling pointers.
How pointers can cause issues when there is shallow copying:
The location of other objects is stored in pointers, which are variables. When we shallow and duplicate the item, an object with pointers will point to the same storage locations as the original object. It means that the shallow copy's pointer will become a dangling pointer if the dynamically allocated memory for the original object is destroyed.
Resource management:
The process of collecting, utilizing, and releasing resources securely and effectively is known as resource management. Memory, file handles, database connections, and network sockets are just a few resources. Because it can aid in preventing a multitude of issues, including memory leaks, file corruption, and crashes, proper resource management is crucial.
Techniques for effective resource management:
Proper resource management can be implemented in C++ using a variety of techniques, such as:
- Making use of smart pointers: A smart pointer is a pointer that automatically controls the lifespan of the item it points to. As a result, we do not have to worry about manually destroying the object after using it.
- Std::shared_ptr and Std::unique_ptr are popular smart pointers in C++. Use std::shared_ptr for resources that several objects can share. The std::unique_ptr is used for resources that can only be owned by one object.
- Utilizing RAII (Resource Acquisition Is Initialization): RAII is a method that guarantees that resources are released when they are no longer needed. The resource is obtained in the object's constructor and released in the destructor to accomplish this.
Conclusion:
- A copy operation known as a shallow copy merely copies the values of the primitive data members, creating a new object with the same values as the original object.
- A deep copy operation produces a new object with exactly the identical values as the original object, including any dynamically allocated memory, as the original object.
- A shallow copy might result in issues like memory leaks and dangling pointers, particularly if the original object includes any pointers to dynamically generated memory.
- However, deep copy is inherently safer than shallow copy because it can be more expensive.
- Smart pointers can be employed to eliminate shallow copy difficulties and to make resource management simpler.