오늘은 C++에서의 얕은 복사와 깊은 복사에 대해서 알아 볼 것이다.
1. 얕은 복사란
- 정의: 객체의 멤버 변수 값만 복사한다. 특히 포인터 변수의 경우, 포인터가 가리키는 주소만 복사하므로, 원본과 복사본이 동일한 메모리를 공유한다
- 문제점
- 원본 객체 또는 복사본 객체 중 하나가 소멸될 때 동적 메모리를 해제하면, 다른 객체가 dangling pointer(더 이상 유효하지 않은 메모리를 가리키는 포인터)가 되어 예기치 않은 동작을 일으킬 수 있다.
- 데이터의 의도치 안흔 변경이 발생할 수 있다.
2. 얕은 복사 예제 코드
#include <iostream>
using namespace std;
class MyClass {
private:
int* data;
public:
MyClass(int value){
data = new int(value); // 동적 메모리 할당
}
// 기본 복사 생성자
MyClass(const MyClass& other) {
data = other.data; // 주소 복사
}
~MyClass() {
delete data;
}
void display() const {
cout << "Data : " << *data << endl;
}
void setData(int value) {
*data = value;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = obj1; // 얕은 복사
obj2.setData(20); // obj2 수정 시 obj1도 영향을 받음
obj1.display();
obj2.display();
return 0;
}
/////// 결과 화면
Data: 20
Data: 20
obj1과 obj2가 동일한 메모리를 공유하기 때문에 obj2의 데이터를 수정하면 obj1도 영향을 받는다.
3. 깊은 복사란
- 정의: 객체의 멤버 변수뿐 아니라, 동적 메모리를 새로 할당하고 데이터를 복사하여 원본과 복사본이 독립적인 메모리 공간을 갖도록 한다.
- 장점
- 복사본과 원본이 완전히 독립적이므로, 한 객체의 수정이 다른 객체에 영향을 미치지 않는다.
- 메모리 누수 및 동적 메모리 관리 문제를 방지할 수 있다.
4. 깊은 복사 예제 코드
#include <iostream>
using namespace std;
class MyClass {
private:
int* data;
public:
MyClass(int value) {
data = new int(value);
}
// 사용자 정의 복사 생성자
MyClass(const MyClass& other) {
data = new int(*other.data); // 동적 메모리를 새로 할당하고 값 복사
}
~MyClass() {
delete data;
}
void display() const {
cout << "Data: " << *data << endl;
}
void setData(int value) {
*data = value;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = obj1; // 깊은 복사
obj2.setData(20); // obj2의 데이터를 수정해도 obj1은 영향 받지 않음
obj1.display();
obj2.display();
return 0;
}
///// 결과 화면
Data: 10
Data: 20
obj2가 원본 객체인 obj1의 데이터를 복사할 때, 새로운 메모리를 할당받아 데이터를 복사한다.
따라서 obj2의 데이터를 수정해도 obj1은 영향을 받지 않는다.
5. 깊은 복사가 필요한 상황
- 클래스가 포인터 멤버를 포함하고 있을 때
- 동적 메모리 할당을 사용하고 있으며, 복사본과 원본이 독립적으로 동작해야 할 때
- 데이터가 공유되지 않고, 각 객체가 자신만의 데이터를 유지해야 할 때
6. 얕은 복사와 깊은 복사의 비교
| 특징 | 얕은 복사 (Shallow Copy) | 깊은 복사 (Deep Copy) |
| 메모리 관리 | 원본과 복사본이 같은 메모리를 공유 | 원본과 복사본이 별도의 메모리를 가짐 |
| 수행 속도 | 빠름 | 느림 (새로운 메모리 할당 필요) |
| 데이터 독립성 | 원본과 복사본이 상호 의존적 | 원본과 복사본이 독립적 |
| 적용 상황 | 데이터 공유가 필요한 경우 | 동적 메모리와 관련된 객체 |
| 문제점 | 메모리 누수, 의도치 않은 변경 발생 | 메모리 사용량 증가 |
7. 결론
- 얕은 복사는 메모리 주소만 복사하여 두 객체가 동일한 메모리를 공유한다. 따라서 동적 메모리 관련 클래스에서는 문제를 일으킬 수 있다.
- 깊은 복사는 새로운 메모리를 할당하여 데이터를 복사하므로, 안전하고 독립적인 객체 복사를 제공한다.
- 포인터 멤버 변수를 가진 클래스에서는 깊은 복사를 구현하는 것이 일반적이다.
'C++' 카테고리의 다른 글
| 전략 패턴을 이용한 정렬 알고리즘 (0) | 2025.01.20 |
|---|---|
| string을 매개변수로 받을 때 &를 사용하는 이유 (0) | 2025.01.07 |
| C++ unique_ptr과 shared_ptr (0) | 2024.12.26 |
| C++ STL vector (0) | 2024.12.24 |
| C++ rand() 사용해서 난수 만들기 (0) | 2024.12.23 |