← Back to C++ Course | Chapter 8: OOP Core | Lesson 12 of 14

C++ Copy Constructor

Default Copy Constructor

If you don't write a copy constructor yourself, the compiler automatically generates a default one that performs a shallow, member-by-member copy from the source object into the new one. This works fine for simple data but becomes dangerous once a class owns a raw pointer.

Example: Default Copy Constructor

cpp
#include <iostream>

class Point {
public:
	int x = 5;
};

int main() {
	Point p1;
	Point p2 = p1; // compiler-generated shallow member-by-member copy
	std::cout << p2.x << std::endl;
	return 0;
}

Defining Custom Copy Constructor

You can define your own copy constructor to control precisely how a new object is initialized from an existing one; it takes a reference to a const object of the same class as its parameter, which lets it read the source without risking (or needing) a copy of its own.

Example: Defining Custom Copy Constructor

cpp
#include <iostream>

class Point {
public:
	int x;
	Point(int val) : x(val) {}
	Point(const Point &other) : x(other.x) {
		std::cout << "Copy constructor called" << std::endl;
	}
};

int main() {
	Point p1(5);
	Point p2 = p1;
	std::cout << p2.x << std::endl;
	return 0;
}

Shallow Copy vs Deep Copy

A shallow copy duplicates a pointer's address, leaving both the original and the copy pointing at the exact same memory — dangerous, since deleting one will leave the other holding a dangling pointer. A deep copy instead allocates fresh memory and duplicates the actual data, so each object owns its own independent copy.

Example: Shallow Copy vs Deep Copy

cpp
#include <iostream>

class Buffer {
public:
	int *data;
	Buffer(int val) { data = new int(val); }
	Buffer(const Buffer &other) {
		data = new int(*other.data); // deep copy: separate memory
	}
	~Buffer() { delete data; }
};

int main() {
	Buffer b1(10);
	Buffer b2 = b1;
	std::cout << *b1.data << " " << *b2.data << std::endl;
	return 0;
}

Copy Constructor in Function Calls

The copy constructor fires automatically whenever an object is passed by value into a function, or returned by value out of one, which is why passing large objects by value can be surprisingly expensive — every call triggers a full copy unless move semantics kick in instead.

Example: Copy Constructor in Function Calls

cpp
#include <iostream>

class Point {
public:
	int x;
	Point(int val) : x(val) {}
	Point(const Point &other) : x(other.x) {
		std::cout << "Copied" << std::endl;
	}
};

void showPoint(Point p) {
	std::cout << p.x << std::endl;
}

int main() {
	Point p(5);
	showPoint(p);
	return 0;
}

Preventing Object Copying

You can prevent a class's objects from ever being copied at all by explicitly deleting the copy constructor with '= delete'. This is the standard technique used by types like std::unique_ptr, which are designed to have exactly one owner and must never be duplicated.

Example: Preventing Object Copying

cpp
#include <iostream>

class Resource {
public:
	Resource() {}
	Resource(const Resource &) = delete;
};

int main() {
	Resource r1;
	// Resource r2 = r1; would fail to compile: copy constructor deleted
	std::cout << "Resource created, copying disabled" << std::endl;
	return 0;
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.