얕은 복사와 깊은 복사 / 복사 생성자 및 대입 연산자 행동 절차
얕은 복사와 깊은 복사
얕은 복사 (Shallow Copy)
멤버 데이터를 비트열 단위로 똑같이 복사함
(메모리 영역 값을 그대로 복사)
ex (a1 클래스를 얕은 복사, b 클래스는 동적 할당, a 클래스와 b 클래스는 생명 주기를 같이 함)
Stack : a1 [ q 0x1000 ] - Heap 0x1000 b [ ]
Stack : a2 [ q 0x1000 ]
Stack : a3 [ q 0x1000 ]
메모리 영역을 그대로 복사해오기 때문에 동일한 주소 값을 가지고 있다.
위와 같은 조건일 때 a1, 2, 3가 전부 동일한 Heap 영역의 b 클래스를 가리키고 있기 때문에 b 클래스는 생성자 호출을
한 번만 하게 되고 소멸자 호출은 세 번을 하게 되면서 에러가 발생한다.
깊은 복사 (Deep Copy)
멤버 데이터가 참조(주소) 값이라면 데이터를 새로 만들어준다.
(원본 객체가 참조하는 대상까지 새로 만들어서 복사)
ex
Stack : a1 [ q 0x1000 ] - Heap 0x1000 b [ ]
Stack : a2 [ q 0x2000 ] - Heap 0x2000 b [ ]
Stack : a3 [ q 0x3000 ] - Heap 0x3000 b [ ]
얕은 복사의 상황을 한 번에 해결할 수 있다. a 클래스들은 각각의 서로 다른 b 클래스 객체를
가지게 된다.
깊은 복사를 해주기 위해서는 복사 대입 연산자를 재정의해서 사용하면 된다.
복사 생성자 행동 절차
1. 암시적 복사 생성자
- 부모 클래스가 있다면 부모 클래스의 복사 생성자 호출
- 멤버 클래스(포인터가 아닌 일반적으로 클래스를 가지고 있는 상태를 말함)의 복사 생성자 호출
- 두 경우가 모두 아니고 멤버의 타입이 기본 타입이라면 메모리 복사, 즉 얕은 복사를 하게 된다.
2. 명시적 복사 생성자
- 부모 클래스의 기본 생성자 호출
- 멤버 클래스의 기본 생성자 호출
중요한 포인트는 명시적으로 복사 생성자를 정의하게 되면 그 이후부터는 프로그래머가 모든
복사와 관련되서 핸들링해야 한다는 점이다. 암시적 때처럼 컴파일러가 자동적으로 복사 생성자를 호출해주지
않기 때문에 프로그래머는 따로 복사 생성자를 호출해야 한다. 만약 이 부분을 놓치게 되면 복사가 완전히
이루어지지 않고 짤리는 부분이 생기거나 할 수 있다.
복사 대입 연산자 행동 절차
1. 암시적 복사 대입 연산자
- 부모 클래스의 복사 대입 연산자 호출
- 멤버 클래스의 복사 대입 연산자 호출
- 멤버가 기본 타입일 경우 메모리 복사(얕은 복사)
2. 명시적 복사 대입 연산자
- 프로그래머가 모든 걸 알아서 핸들링해야 함