1. Home
C++ Tutorial

Explore C++ Tutorials: Exploring the World of C++ Programming

Discover comprehensive C++ tutorials designed for beginners and advanced programmers alike. Enhance your coding skills with step-by-step guides and practical examples.

  • 77 Lessons
  • 15 Hours
right-top-arrow
19

Copy Constructor in C++: Deep Copy, Syntax, and Examples

Updated on 24/09/2024428 Views

A copy constructor is a special type of constructor within a class. We use the copy constructor in C++ to create a brand new object by replicating the data and state of an existing object of the same class. It is a core operation in many C++ programs.

Copy constructors fundamentally give us the control to decide how our objects are duplicated, ensuring the correct and efficient behavior of our programs.

Let us imagine we have a blueprint for a perfect AI model. We would not want to recreate the entire blueprint every time we need a new AI model. Instead, we would simply make a copy of the original blueprint. A copy constructor in C++ serves a similar purpose but for objects instead of blueprints.

Why Do We Use Copy Constructor in C++?

We use the copy constructor in C++ as it allows us to copy objects properly and effectively. Why bother with proper copying? The use of copy constructor in C++ is common due to these two reasons:

  1. Preventing shallow copies: If we just blindly copy an object that contains pointers (which point to other data in memory), we might end up with multiple objects sharing the same piece of data. If one object modifies this data, it affects all the others and this is not the behavior we want. Copy constructors allow us to create "deep copies," where each object gets its own independent copy of the data.
  1. Managing resources: Some objects own resources, like files or network connections. A copy constructor in C++ lets us define how these resources are handled during copying. Should the new object share the resource (which can be risky), or should it get its own copy? We get to decide that.

Implicit vs. Explicit Copy Constructors

C++ is helpful and if we don't write our own copy constructor, the compiler automatically generates one for us. This default copy constructor in C++ performs a member-wise copy, meaning it copies the value of each data member from the old object to the new one.

So, when do we need to roll up our sleeves and write a custom (explicit) copy constructor?

  1. Dynamic memory (pointers): If our class has pointers that manage memory allocated with new, we almost always need a custom copy constructor to perform a deep copy.
  1. Resource-owning classes: If our object "owns" external resources, we will want to decide how those resources should be handled during copying.
  1. Non-trivial copy semantics: Sometimes, the simple member-wise copy isn't enough. We might have objects that need special handling when being copied.

We will discuss the above three in more detail later in the article. We will also cover why custom constructors in C++ are the solution.

Copy Constructor in C++ Syntax and Mechanics

Here is the standard syntax for declaring and defining a copy constructor in C++:

MyClass(const MyClass& other); 

We must utilize the const reference parameter to avoid unnecessary copying of the source object.

The blueprint for a copy constructor follows this simple pattern:

class MyClass {

public:

    MyClass(const MyClass& other); // Copy constructor declaration

    // ... other members (data, functions) ...

};

// Copy constructor definition (usually outside the class)

MyClass::MyClass(const MyClass& other) {

    // Code to copy data members from 'other' to this object

}

Here are the core components of the copy constructor in C++:

  • MyClass: This is the name of our class. The copy constructor has the same name as the class.
  • const MyClass& other: This is the parameter that represents the object we are copying from (the "source" object). In this parameter:
    • const: Ensures the source object isn't accidentally modified during copying.
    • & (Reference): Prevents an endless loop of copying (since passing by value would trigger another copy constructor call).

Copy Constructor in C++ Example Program

Here is an example program for copy constructor in C++:

Code:

#include <iostream>

#include <algorithm>

#include <stdexcept>

class DynamicArray {

public:

    DynamicArray(int size) : size(size), data(new int[size]) {} 

    // Copy constructor (deep copy)

    DynamicArray(const DynamicArray& other) : size(other.size), data(new int[size]) {

        std::copy(other.data, other.data + size, data); 

    }

    ~DynamicArray() {

        delete[] data;

    }

    int& operator[](int index) { 

        if (index < 0 || index >= size) {

            throw std::out_of_range("Index out of bounds");

        }

        return data[index];

    }

    // Getter function for size

    int getSize() const {

        return size;

    }

private:

    int* data;

    int size;

};

int main() {

    DynamicArray arr1(5);

    // Initialize arr1

    for (int i = 0; i < arr1.getSize(); ++i) { // Use the getter for size

        arr1[i] = i * 10;

    }

    DynamicArray arr2 = arr1; // Deep copy using the copy constructor

    // Modify arr2 without affecting arr1

    arr2[0] = 99;

    std::cout << "arr1: ";

    for (int i = 0; i < arr1.getSize(); ++i) { // Use the getter for size

        std::cout << arr1[i] << " "; 

    }

    std::cout << std::endl;

    std::cout << "arr2: ";

    for (int i = 0; i < arr2.getSize(); ++i) {  // Use the getter for size

        std::cout << arr2[i] << " "; 

    }

    std::cout << std::endl;

return 0;

}

In this copy constructor in C++ program, arr2 is a shallow copy of arr1. Modifying arr2 also modifies arr1 because they share the same underlying data array. This leads to unexpected behavior and potential crashes.

Output:

arr1: 0 10 20 30 40

arr2: 99 10 20 30 40

If you wish to learn how to code in C++, you can check out upGrad’s software engineering courses.

Member-wise Copy (Shallow Copy): The Default Behavior

If we don't write our own copy constructor, C++ provides a default one for us. This default version does a member-wise copy:

  1. It creates a new object of our class.
  2. It copies the value of each data member from the source object directly into the corresponding data member of the new object.

This is fine for simple classes with basic data types. But there's a catch. Let us assume our class has a pointer member that dynamically allocates memory (e.g., an array). A shallow copy will simply copy the pointer's value (the memory address), not the data it points to. This means both the original and copied objects end up pointing to the same memory.

This can lead to serious problems:

  • Double deletion: If both objects try to deallocate the same memory in their destructors, our program crashes.
  • Unexpected modification: If one object changes the data at that memory address, the other object sees the change too.

Deep Copy: The Solution

Deep copy is the solution to the shallow copy problem. It involves creating a completely new and separate copy of any dynamically allocated data.

Here is an example of deep copy with a copy constructor:

class MyClass {

public:

    // ...

    MyClass(const MyClass& other) : data(nullptr) {

        if (other.data) {

            // Allocate new memory for our copy

            data = new int[other.size]; 

// Copy the elements

            std::copy(other.data, other.data + other.size, data);

        }

        size = other.size;

    }

// ... other members (destructor, etc.) 

private:

    int* data;  // Pointer to dynamically allocated array

    int size;

};

In the above C++ copy constructor example, the copy constructor ensures that the new object gets its own, distinct copy of the array data. No more sharing, no more trouble.

When Do We Need a Custom Copy Constructor in C++?

C++'s default copy constructor (member-wise copy) is often sufficient for simple classes. However, in certain situations, we need to step in and take control of how copying happens. Let us discuss the key scenarios in more detail.

Pointer Members: Avoiding Dangling Pointers and Double Deletion

When our class contains raw pointers (int*, char*, etc.) that manage dynamically allocated memory (using new), the default copy constructor becomes a liability.

Problem: The default copy constructor will merely copy the pointer value (the memory address), not the data it points to. This means both the original and the copied object end up pointing to the same piece of dynamically allocated memory. This leads to:

  • Dangling pointers: If one object deletes the memory, the other object's pointer is left pointing to invalid memory, causing undefined behavior.
  • Double deletion: If both objects try to delete the same memory, our program will crash.

Solution: Write a custom copy constructor to perform a deep copy of the dynamically allocated data:

class MyClass {

public:

    // ... 

    MyClass(const MyClass& other) {

        // ... (deep copy other.data)

    }

    // ...

private:

    int* data;

};

Resource-Owning Classes: Managing Ownership

Classes that own resources like file handles, network sockets, or database connections need special care during copying.

Problem: We need to decide whether the copied object should:

  • Share the resource: This might seem efficient, but it can lead to unexpected behavior if both objects try to use the resource simultaneously or close it at different times.
  • Own a duplicate of the resource: This avoids conflicts but might be costly if resources are limited.

Solution: A custom copy constructor lets us define the correct resource management strategy, whether it's sharing, duplicating, or something else entirely.

Non-Trivial Copy Semantics: Tailored Copying

Sometimes, the simple act of copying each member variable is not enough.

Example: Imagine a class representing a bank account. We would not want to create a copy of the account that shares the same balance! In this case, we need a custom copy constructor to create a new account with the same initial balance but as a separate entity.

Final Tips

Copy constructors may seem like a subtle detail of C++, but their impact on code correctness and resource management is undeniable. When you understand how to write effective copy constructors, you empower your classes to handle object duplication gracefully and safely.

When in doubt, opt for deep copying to ensure that your copied objects are truly independent entities. This prevents unexpected surprises and errors down the road. By prioritizing correct copy construction, you lay a solid foundation for building robust, maintainable, and efficient C++ applications. So, the next time you encounter a class with pointers, resources, or unique copying requirements, remember the power of the copy constructor in C++, it's your key to creating well-behaved objects that play nicely with others in the world of C++.

If you wish to learn programming languages such as C++, you can check out upGrad’s computer science programs such as the Master’s in Computer Science Program.

Frequently Asked Questions

  1. What are copy constructors in C++?

Copy constructors are special member functions in C++ classes that create a new object by initializing it with the values of an existing object of the same class.

  1. What is the difference between constructor and copy constructor?

A regular copy constructor cpp creates an object from scratch, while a copy constructor creates a new object as a copy of an existing object.

  1. Why do we use references in copy constructor in C++?

We use references in a copy constructor in C++ to avoid an infinite recursion loop that would occur if the constructor took its argument by value, creating yet another copy.

  1. What is the syntax of a copy constructor?

The syntax is: ClassName(const ClassName& other);

  1. Should a copy constructor be defined explicitly?

You should define a copy constructor in C++ explicitly if your class has dynamically allocated memory (e.g., using new) or contains non-static members that also need deep copying.

  1. How to define a custom copy constructor?

To define a custom copy constructor, follow the syntax and write code in the body to copy the data members of the original object into the new object.

  1. Can a copy constructor be private?

Yes, a copy constructor in C++ can be private. This prevents objects of the class from being copied outside of the class itself.

  1. What is the benefit of a copy constructor?

Copy constructors allow us to create duplicates of objects, which is useful for passing objects by value to functions, returning objects by value, and creating new objects initialized with the state of existing objects.

Abhimita Debnath

Abhimita Debnath

Abhimita Debnath is one of the students in UpGrad Big Data Engineering program with BITS Pilani. She's a Senior Software Engineer in Infosys. She…Read More

Need Guidance? We're Here to Help!
form image
+91
*
By clicking, I accept theT&Cand
Privacy Policy
image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
right-top-arrowleft-top-arrow

upGrad Learner Support

Talk to our experts. We’re available 24/7.

text

Indian Nationals

1800 210 2020

text

Foreign Nationals

+918045604032

Disclaimer

upGrad does not grant credit; credits are granted, accepted or transferred at the sole discretion of the relevant educational institution offering the diploma or degree. We advise you to enquire further regarding the suitability of this program for your academic, professional requirements and job prospects before enr...