Copy constructors are invoked in the following scenarios:

  1. When initializing one object of a class from another object (or reference) of the same class, the copy constructor is automatically called.
  2. When a function parameter is a class object passed by value, the copy constructor is called as the argument is copied into the parameter. (The compiler may optimize this away.)
  3. When a function returns a class object, the copy constructor is called. (Note: the compiler may optimize this, making the copy unobservable.)
#include<ctime>
#include<cstdlib>
#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
using namespace std;

class A {
public:
	A():data(0){}
	A(const A& a){
		data = a.data;
		cout << "copy constructor called\n";
	}
	A& operator=(const A&a){
		data = a.data;
		cout << "assignment operator called\n";
		return *this;
	}

	int data;
};

void fun1(A a) {
	return ;
}

A fun2() {
	A a;
	return a;
}

int main() {
	A a;
	A b(a);          // initialize b from a — copy constructor
	A c = a;         // initialize c from a — this is initialization, not assignment
	fun1(a);         // pass by value — copies argument to parameter
	A d = fun2();    // return by value — may be optimized away by the compiler
	d = a;           // d is already initialized — this is assignment, not copy construction

	return 0;
}

Note on scenario 3 (returning a class object): the compiler typically applies copy elision to reduce unnecessary copies, so the actual behavior depends on the compiler and optimization flags. With g++, disabling optimization via g++ xxx.cpp -fno-elide-constructors produces:

copy constructor called
copy constructor called
copy constructor called
copy constructor called
copy constructor called
assignment operator called

With default optimization enabled:

copy constructor called
copy constructor called
copy constructor called
assignment operator called

The compiler’s optimization strategy: it first checks for copy elision; if that’s not supported, it looks for a move constructor; if neither is available, it falls back to the copy constructor. See move semantics and copy elision for more details.

Finally, note the difference between A c = a; (initialization — copy constructor) and d = a; (assignment — assignment operator).