1. 값 복사(Value Copy) vs 주소 복사(Address Copy)
"무엇을 복사했는가?"에 대한 형태적 구분입니다.
값 복사 (Value Copy)
객체가 가진 값 자체를 복사합니다. C++의 기본 대입 연산자나 복사 생성자는 기본적으로 값 복사입니다.
int b = a;
또는
A a2 = a1;
• 특징 : 복사된 두 변수는 메모리상에서 서로 완전히 독립적입니다.
주소 복사 (Address Copy)
데이터가 저장된 메모리 주소값만 복사합니다.
int* p2 = p1;
또는
참조(&)를 통한 전달.
• 특징 : 복사본과 원본이 같은 메모리 주소를 가리키며 실체를 공유합니다.
2. 얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy)
"복사 결과가 어떤 의미를 갖는가?"에 대한 결과적 구분입니다.
이 둘 간의 구분은 객체 내부에 "포인터(또는 소유 자원)" 가 있을 때만 의미가 있습니다.
얕은 복사 (Shallow Copy)
객체 내부의 포인터 값(주소)만 복사하는 방식입니다.
• 결과 : 내부 포인터가 가리키는 대상은 복사되지 않고 원본과 공유됩니다.
• 위험성 : 원본 객체가 소멸되어 메모리가 해제될 때, 복사본이 "이미 해제된 메모리"를 가리키게 되어 런타임 에러를 유발할 수 있습니다.
깊은 복사 (Deep Copy)
포인터가 가리키는 실제 내용물까지 새로 생성하여 복사하는 방식입니다.
• 결과 : 복사 이후 두 객체는 힙(Heap) 메모리 영역에서도 완전히 독립적인 상태가 됩니다.
• 구현 : 개발자가 직접 복사 생성자나 대입 연산자에서 new 등을 이용해 자원을 할당해야 합니다.
3. 두 개념의 관계 : 서로 다른 축의 결합
값, 주소 복사와 얕은, 깊은 복사는 서로 대립하는 개념이 아니라, 서로 기준이 다릅니다.
그래서 "값 복사는 깊은 복사다" 라거나 "주소 복사는 얕은 복사" 라 라고 말하는 것은 성립이 안됩니다.
다만 다음과 같은 경우들은 의미가 있습니다.
• 값 복사이면서 얕은 복사인 경우 : 객체를 값으로 복사했는데, 그 안에 포인터 멤버가 있어 주소만 복사된 경우 (C++ 기본 동작).
• 값 복사이면서 깊은 복사인 경우 : 객체를 값으로 복사하면서, 내부 포인터가 가리키는 자원까지 새로 할당하도록 설계한 경우.
• 주소 복사 : 이 경우 실체를 공유하는 것이 목적이므로 얕은/깊은 복사의 논의가 필요 없습니다.
4. 포인터가 없다면 구분은 무의미하다
만약 구조체나 클래스 내부에 포인터가 없다면 어떻게 될까요?
struct B {
int x;
float y;
};
B b2 = b1; // 항상 완전히 독립적인 복사본 생성
이 경우 얕은 복사와 깊은 복사의 결과가 동일합니다. 즉, 포인터가 없는 경우에는 두 개념을 구분할 이유 자체가 없습니다.
5. 최종 정리 (Deep Dive)
• 값 / 주소 복사 : 복사의 '형태' (무엇을 넘겼는가?)
• 얕은 / 깊은 복사 : 복사의 '의미' (자원까지 새로 만들었는가?)
한 걸음 더 나아가기 C++의 std::vector나 std::string 같은 표준 라이브러리들은 문법적으로는 **'값 복사'**의 형태를 취하지만, 내부적으로는 자원을 새로 할당하는 **'깊은 복사'**를 수행하도록 설계되어 있습니다. 이것이 우리가 복사 생성자를 공부하고 직접 구현해야 하는 실무적인 이유입니다.
얕은 복사와 깊은 복사는 "포인터가 있을 때"만 고민하면 됩니다. 포인터가 가리키는 대상까지 새로 만들었다면 깊은 복사, 주소만 가져왔다면 얕은 복사입니다!
'C++' 카테고리의 다른 글
| new 할당과 초기화 (0) | 2026.01.09 |
|---|---|
| 스택(Stack)과 힙(Heap) : 책임과 수명의 차이 (0) | 2026.01.08 |
| 매크로란 무엇인가? (0) | 2026.01.05 |
| 전방 선언 (0) | 2026.01.05 |
| TCHAR 에 대한 이해 (0) | 2026.01.04 |