얕은 복사와 깊은 복사
- 얕은 복사 (Shallow Copy)
객체를 복사할 때 객체의 멤버 변수를 단순히 복사하는 방식이다. 단순한 기본 자료형이 멤버 변수일 때는 문제가 없지만, 멤버 변수가 포인터 변수라면 포인터 변수의 값을 복사하기 때문에, 즉 주소값을 복사하기 때문에 문제가 생길 수 있다. 주소값을 복사했기 때문에 원본 객체와 복사된 객체의 해당 포인터 멤버 변수는 같은 주소를 가리키고 있고, 하나의 객체에서 해당 변수가 가리키고 있는 값에 대한 수정이 이루어지면 다른 객체에까지 영향을 미치게 된다.
예를 들어 다음 코드를 확인하자.
#include <iostream>
using namespace std;
class ShallowCopy {
public:
int* data;
ShallowCopy(int val) {data = new int(val);}
~ShallowCopy() {delete data;}
};
int main() {
ShallowCopy obj1(10);
ShallowCopy obj2 = obj1;
*(obj2.data) = 20;
cout << *(obj1.data) << endl;
return 0;
}
이때 obj1 의 멤버 변수 data 는 포인터 변수이다. 따라서 obj2 가 obj1 의 멤버 변수를 복사할 때 주소값을 복사하고, 같은 곳을 가리키게 된다. 따라서 obj2 의 data 를 변경했는데, cout 으로 obj1 의 멤버 변수를 출력하면 20 이 출력된다. 또한 각 객체의 소멸자를 호출하면서 같은 주소를 반환하려하니 이 부분에서도 오류가 발생하게 된다.
- 깊은 복사 (Deep Copy)
객체를 복사할 때 객체의 실제 값을 복사하는 방식이다. 포인터 멤버 변수가 있는 경우에는 원본 객체의 포인터 멤버 변수가 가리키도 있는 주소가 아니라 원본 객체가 가지고 있는 값을 사본에 복사한다. 즉 새로운 메모리 공간을 할당하고, 그 공간에 값을 대입한다. 따라서 사본과 원본이 메모리를 공유하는 문제가 없다.
복사 생성자 (Copy Constructor)
복사 생성자는 객체의 복사 생성시 호출되는 특별한 생성자이다. 한 클래스에 오직 한 개만 선언 가능하다.
복사 생성자는 보통 생성자와 클래스 내에 중복 선언 가능하며, 클래스에 대한 참조 매개 변수를 가지는 독특한 생성자이다.
기본적인 문법은 다음과 같다.
class ClassName {
....
ClassName(const ClassName& objectname);
....
};
ClassName::ClassName(const ClassName& objectname) {
....
}
즉 복사 생성자의 구현부를 통해서 포인터 변수가 멤버 변수로 존재하는 경우 해당 값을 복사하도록 설정할 수 있다.
이를 다른 함수에서 사용할 때는 다음과 같이 사용한다.
ClassName copy_object(original_object);
이러한 복사 생성자는 따로 선언하지 않더라도 컴파일 과정에서 컴파일러에 의해 자동으로 생성된다. 단 이때 생성되는 디폴트 복사 생성자는 얕은 복사만 수행한다. 따라서 깊은 복사가 필요한 경우라면 따로 복사 생성자를 선언하고, 구현해주어야 한다.
'Language > C & C++' 카테고리의 다른 글
[C++] 프렌드(friend)를 통한 클래스 멤버 접근 (0) | 2024.10.27 |
---|---|
[C/C++] 헤더파일 분할 작성과 헤더파일 중복 선언 방지 (0) | 2024.10.13 |
[C++] 값에 의한 호출(call by value)과 주소에 의한 호출(call by address) 그리고 참조에 의한 호출(call by reference) (0) | 2024.10.13 |
[C++] 동적 메모리 할당 및 반환 (0) | 2024.10.13 |
[C++] 클래스(class)와 객체(object) 선언 (0) | 2024.09.18 |