오늘은 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. 결론

  • 얕은 복사메모리 주소만 복사하여 두 객체가 동일한 메모리를 공유한다. 따라서 동적 메모리 관련 클래스에서는 문제를 일으킬 수 있다.
  • 깊은 복사는 새로운 메모리를 할당하여 데이터를 복사하므로, 안전하고 독립적인 객체 복사를 제공한다.
  • 포인터 멤버 변수를 가진 클래스에서는 깊은 복사를 구현하는 것이 일반적이다.

+ Recent posts