본문 바로가기

C++

[C++] 복사 생성자(copy constructor)

복사 생성자(copy constructor)란?

 

복사 생성자란 객체의 복사본을 생성할 때 호출되는 생성자이다. 복사 생성자도 생성자와 마찬가지로 정의하지 않으면 컴파일러가 자동으로 만들어준다.

 

복사 생성자의 형태는 다음과 같다.

 

클래스이름(const 클래스이름 &변수이름);

 

다음 예제는 복사 생성자를 사용하였고 생성자와 마찬가지로 멤버 변수를 초기화하였다.

 

#include <iostream>
using namespace std;

class TestClass
{
public:
	TestClass(int param)
		: num(param)	//생성자 초기화
	{ cout << "TestClass()" << endl; }

	//복사 생성자
	TestClass(const TestClass& ref)
		: num(ref.num)	//복사 생성자 초기화
	{
		cout << "TestClass() 복사 생성자" << endl;
	}

private:
	int num;
};

void TestFunc(TestClass a)
{
	cout << "TestFunc()" << endl;
}

int main()
{
	TestClass a(10);
	TestClass b(a);

	return 0;
}

 

결과값:

TestClass()
TestClass() 복사 생성자

 

TestClass 객체 b를 생성하고 객체 a를 복사하자 복사 생성자가 호출되었다. 복사 생성자를 따로 정의하지 않아도 결과는 똑같다. 하지만, 복사 생성자를 정의해줘야 하는 경우가 있다.

 

 

다음 예제는 TestClass 객체를 매개변수로 받는 함수를 호출하였다.

 

#include <iostream>
using namespace std;

class TestClass
{
public:
	TestClass(int param)
		: num(param)	//초기화
	{ cout << "TestClass()" << endl; }

	//복사생성자
	TestClass(const TestClass& ref)
		: num(ref.num)	//초기화
	{
		cout << "TestClass() 복사생성자" << endl;
	}

private:
	int num;
};

void TestFunc(TestClass a)
{
	cout << "TestFunc()" << endl;
}

int main()
{
	TestClass a(10);
	TestFunc(a);

	return 0;
}

 

결과값:

TestClass()
TestClass() 복사생성자
TestFunc()

 

TestClass 객체를 매개변수로 받는 함수를 호출하자 복사 생성자가 호출되었다. 매개변수로 넘어갈 때 객체 a인 원본을 두고 복사본이 생성된 것이다. 굳이 필요 없는 객체가 선언된 것이다.

 

해결방법은 간단하다. TestFunc가 매개변수를 받을 때 참조자로 받으면 된다. void TestFunc(TestClass &a)로 고치면 필요없는 객체가 생성되지 않는다.

 

 

다른 예제로 포인터가 멤버 변수일 때이다.

 

#include <iostream>
using namespace std;

class TestClass
{
public:
	TestClass(int param)
	{
		num = new int;
		*num = param;
	}

	//복사 생성자
	TestClass(const TestClass& ref)
	{
		num = ref.num;
	}

	//소멸자 동적 할당 메모리 해제
	~TestClass()
	{
		delete num;
	}

private:
	int *num;
};

int main()
{
	TestClass a(10);
	TestClass b(a);

	return 0;
}

 

결과값:

에러, 프로그램종료

 

위 예제에서 복사 생성자를 없애더라도 컴파일러가 동일하게 복사 생성자를 만들 것이다. 객체 b는 객체 a의 복사를 통해 a.num과 b.num가 같은데 이미 메모리가 해제된 상태에서 또 메모리를 해제하는 과정에서 에러가 발생한다. 즉, 얕은복사(shallow copy)가 수행되어서 에러가 발생한 것이므로 깊은복사(deep copy)가 되도록 복사 생성자를 반드시 적절하게 정의해 줘야 한다.

 

//복사 생성자 재정의
TestClass(const TestClass& ref)
{
	num = new int;
	*num = *ref.num;
}