본문 바로가기
Language/C++

복사 생성자 사용시 유의할 점

by W00gie 2021. 2. 15.

이미 생성된 객체로부터 값을 복사해 같은 값, 타입의 객체를 만들때

우리는 다음과 같은 형식의 생성자를 이용한다

#include <string.h>
#include <stdio.h>
#pragma warning(disable:4996)

class Human
{
private:
	char name[12];
	int age;

public:
	Human(const char* aname, int aage)
	{
		strcpy(name, aname);
		age = aage;
	}

	void intro() {
		printf("이름=%s,나이 =%d\n", name, age);
	}

};

int main()
{
	Human kim("woogie", 26);
	kim.intro();
	Human Lee = kim; //복사 생성자 사용
	Lee.intro();
	return 0;
}

복사 생성자의 경우 없을 경우 컴파일러가 디폴트 생성자를 자동으로 만들어 주기 때문에 위와 같은 예제도 잘 작동한다. 하지만 디폴트 복사 생성자를 이용한 사본 객체 생성은 일대일 복사만을 수행하기 때문에 위험하다.

 

컴파일러를 통해 생성되는 디폴트 복사 생성자의 내부는 다음과 같은 구조다.

Human(const Human& other)
{
	strcpy(name, other.name);
	age = other.age;
}

 

위와 같은 디폴트 생성자는 단순히 일대일 대응을 할 뿐이어서 객체가 포인터기반의 변수를 가지는 경우 완전히 독립된 객체가 아니라 한 가지 변수를 공유하게 된다. (같은 address를 지목)

이런 식으로 address를 공유하게 되면 한 객체가 파괴될 때 남아있는 변수의 멤버도 함께 파괴된다는 점이다.

 

 

 

포인터를 가진 클래스는 완전히 독립된 복사 객체를 가지기 위해서는 별도의 복사생성자 작성이 필요하다.

 

#include <stdio.h>
#include <string.h>

class Human
{
private :
	char *pname;
	int age;

public :
	Human(const char* aname, int aage) {
		pname = new char[strlen(aname) + 1];
		strcpy(pname, aname);
		age = aage;
	}

	Human(const Human& other) {
		pname = new char[strlen(other.pname) + 1];   //동적할당을 거쳐 깊은 복사 수행
		strcpy(pname, other.pname);
		age = other.age;
	}
};