이 문서의 내용
복사 생성자
복사 생성자(Copy constructor)는 별도 정의하지 않더라도 컴파일러가 자동으로 생성하는 Constructor입니다.
얕은 복사에서는 디폴트 복사 생성자를 호출합니다.
복사 생성자를 재정의하려면 객체와 동일한 타입의 참조(&)를 인자로 받는 생성자를 구성합니다.
얕은 복사
얕은 복사(Shallow copy)는 디폴트 복사 생성자를 사용하는 객체 간 복사입니다.
다음 코드는 얕은 복사가 실행되는 간단한 예제입니다.
#include <iostream>
#include <cstring>
class People
{
public:
char* name;
int age;
People(const char* _name, int _age)
{
name = new char[strlen(_name) + 1];
strcpy(name, _name);
age = _age;
}
};
int main()
{
People p0 = People("foo", 18);
People p1 = p0;
std::cout << reinterpret_cast<void *>(p0.name) << " " << p0.name << " " << p0.age << std::endl;
std::cout << reinterpret_cast<void *>(p1.name) << " " << p1.name << " " << p1.age << std::endl;
}
코드 | 비고 | |
클래스에서 정의한 생성자로 |
||
프로그램을 실행하고 출력 결과를 확인합니다.
0xc96f18 foo 18
0xc96f18 foo 18
멤버 변수 char* name에 대해서 두 객체가 동일한 힙 메모리 주소 값을 가리키고 있습니다.
따라서 어떤 객체가 char* name 멤버 변수를 delete하게 되면 다른 객체에도 영향을 주게 됩니다.
테스트를 위해 코드를 수정합니다. 참조 객체가 delete 되어 값을 확인하지 못하는 것을 알 수 있습니다.
People p0 = People("foo", 18);
People p1 = p0;
delete[] p1.name;
std::cout << reinterpret_cast<void *>(p0.name) << " " << p0.name << " " << p0.age << std::endl;
std::cout << reinterpret_cast<void *>(p1.name) << " " << p1.name << " " << p1.age << std::endl;
깊은 복사
깊은 복사(Deep copy)는 얕은 복사와 달리 디폴트 복사 생성자를 사용하지 않고 재정의합니다.
#include <iostream>
#include <cstring>
class People
{
public:
char* name;
int age;
People(const char* _name, int _age)
{
name = new char[strlen(_name) + 1];
strcpy(name, _name);
age = _age;
}
People(const People& _source)
{
std::cout << "Deep copied" << std::endl;
name = new char[strlen(_source.name) + 1];
strcpy(name, _source.name);
age = _source.age;
}
};
int main()
{
People p0 = People("foo", 18);
People p1 = p0;
std::cout << reinterpret_cast<void *>(p0.name) << " " << p0.name << " " << p0.age << std::endl;
std::cout << reinterpret_cast<void *>(p1.name) << " " << p1.name << " " << p1.age << std::endl;
delete[] p1.name;
std::cout << std::endl;
std::cout << "Post deleted" << std::endl;
std::cout << reinterpret_cast<void *>(p0.name) << " " << p0.name << " " << p0.age << std::endl;
}
코드 | 비고 | |
깊은 복사 이후 원본 객체의 멤버 변수 |
||
원본 객체의 멤버 변수가 |
테스트 코드를 실행하면 얕은 복사와의 차이점을 두 가지 확인 할 수 있습니다.
Deep copied
0x786f18 foo 18
0x786f28 foo 18
Post deleted
0x786f28 foo 18
우선 깊은 복사가 이뤄진 이후 두 객체의 멤버 변수 char* name이 가리키는 주소 값이 서로 다릅니다.
따라서 한쪽이 delete 된 이후에도 남은 한쪽은 여전히 유효한 값을 나타냅니다.
정리 및 복습
복사 생성자(Copy constructor)는 임의 정의하지 않더라도 컴파일러에 의해서 자동 생성됩니다.얕은 복사(Shallow copy)는 디폴트 복사 생성자를 사용합니다.- 얕은 복사가 실행되면 멤버 변수의
포인터 변수가 원본과 서로 동일한 메모리 주소를 참조합니다. 깊은 복사(Deep copy)는 복사 생성자를 재정의하여 사용합니다.- 깊은 복사가 실행되면 멤버 변수의
포인터 변수가 원보과 서로 다른 메모리 주소를 참조합니다.
'C++ > C, C++, STL' 카테고리의 다른 글
클래스(class)와 구조체(struct)의 차이 (0) | 2024.02.08 |
---|---|
자기 자신을 나타내는 this 포인터 (0) | 2024.02.04 |
이중 포인터와 동적 다차원 배열에 대한 이해 (0) | 2024.02.04 |
포인터(Pointer)와 주소 연산자(&), 역참조 연산자(*) 그리고 주소의 증감 연산 처리 (0) | 2024.02.04 |
표준 입출력을 위한 std::cout, std::cin (0) | 2024.02.03 |