1. Shallow Copy
Shallow Copy는 직역하자면 얕은 복사라고 할 수 있다. 얕은 복사라는 이름에 걸맞게 Shallow Copy는 객체를 완벽하게 복사하는 것이 아니라 객체가 가리키는 포인터만을 복사해 주는 방식이라고 할 수 있다. 예를 들어 객체 A를 B에 Shallow Copy하면 B에는 새로운 메모리 공간이 할당되고 거기에 객체 A를 복사하는 것이 아니라, 객체 A의 포인터를 B에 저장하는 식으로 복사를 수행한다.
C++에서 기본 복사 생성자는 바로 이 Shallow Copy를 수행한다. 코드로 보자면 다음과 같다.
class A {
public:
A(char* str);
~A() { delete[] str; }
private:
char* str;
int len;
}
A::A(char* string) {
len = strlen(string);
str = new char[len+1];
strcpy_s(str, len, string);
}
int main() {
A a("abc");
A b = a;
return 0;
}
해당 예제는 문자열을 저장하는 A라는 클래스에 문자열을 동적할당하고 디폴트 복사 생성자를 활용해서 b에 해당 클래스를 복사하는 예제다. 만약 해당 코드를 컴파일하고 실행하려 한다면 소멸자에서 이미 Free한 Data를 Free할수 없다고 에러를 낼 것이다.
이유는 간단하다. 디폴트 복사 생성자는 Shallow Copy를 수행하기 때문이다. b.str은 a.str의 포인터를 가리키는 포인터일 뿐 자기 자신의 메모리 공간을 갖고 있지 않다. 따라서 A나 B 둘 중 하나의 소멸자가 호출되었을 때 해당 문자열의 주소는 delete에 의해서 할당해제되고 나머지 하나의 소멸자가 호출될 때 이미 할당 해제된 메모리 영역을 delete하려고 시도함으로써 에러가 발생하게 되는 것이다.
해당 에러를 발생시키지 않으려면 복사 생성자를 재정의(Override)해서 Deep Copy로 변경시켜 주어야 한다.
2. Deep Copy
Deep Copy는 Shallow Copy와는 다르게 실제 메모리를 할당하고 실제 데이터를 복사하는 방식이라고 할 수 있다. 위 예제에서 Deep Copy를 사용하는 복사 생성자를 정의하자면 다음과 같다.
A::A(const A& a) {
len = a.len;
str = new str[len+1];
strcpy_s(str, len, a.str);
}
위 예제는 복사 생성자를 재정의해서 Deep Copy를 수행한다. 따라서 A의 소멸자와 B의 소멸자가 호출될 때 각 메모리 공간에서 str을 해제해도 에러가 발생하지 않는다.
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 프로그래밍 방법론 / 함수 객체 Functor (0) | 2023.02.13 |
---|---|
C++ 문법 / 템플릿 (0) | 2023.02.13 |
C++ 표준 라이브러리 / 파일입출력 (0) | 2023.02.13 |
C++ 표준 라이브러리 / istream, ostream에 관한 이모저모 (0) | 2023.02.13 |
C++ 문법 / 정적 메서드와 정적 멤버 변수(static) (0) | 2023.02.12 |
댓글