[C++][Python]깊은 복사와 얕은 복사: 개념과 차이점

JUNYOUNG·2024년 11월 26일

CS 기초

목록 보기
6/6
post-thumbnail

깊은 복사(Deep Copy)와 얕은 복사(Shallow Copy)는 객체 복사 시 원본 데이터와 복사본이 어떻게 연결되고 동작하는지를 결정짓는 중요한 개념이다.

C++는 메모리를 개발자가 명시적으로 관리해야 하며, Python은 내부적으로 가비지 컬렉션을 사용하여 메모리를 관리하기 때문에 두 언어의 복사 동작에는 차이가 있다.

이번 글에서는 C++에서의 얕은 복사와 깊은 복사를 먼저 다루고, 이후 Python에서의 얕은 복사와 깊은 복사를 비교하며 실무에서 어떻게 활용할 수 있을지 살펴보겠다.


1. 얕은 복사란?

얕은 복사는 객체의 최상위 레벨만 복사하며, 객체가 참조하는 내부 데이터(메모리 주소)는 복사하지 않는다.

즉, 복사본은 원본과 같은 데이터를 참조하기 때문에, 복사본에서 데이터를 변경하면 원본에도 영향을 미친다.


C++에서의 얕은 복사

C++에서 얕은 복사는 기본 동작이다. 복사 생성자나 대입 연산자를 사용할 때 별도로 구현하지 않는 한, 객체는 얕은 복사를 수행한다.

#include <iostream>
using namespace std;

class Shallow {
public:
    int* data;
    Shallow(int value) {
        data = new int(value); // 동적 메모리 할당
    }
    ~Shallow() {
        delete data; // 동적 메모리 해제
    }
};

int main() {
    Shallow obj1(10);
    Shallow obj2 = obj1; // 얕은 복사 발생

    cout << "obj1 data: " << *obj1.data << endl; // 출력: 10
    cout << "obj2 data: " << *obj2.data << endl; // 출력: 10

    *obj2.data = 20; // obj2를 통해 데이터 변경
    cout << "obj1 data: " << *obj1.data << endl; // 출력: 20 (obj1도 영향을 받음)
    return 0;
}
  • obj1obj2같은 메모리 공간을 공유한다.
  • 문제점: 한쪽에서 데이터를 변경하면 다른 객체에도 영향을 준다.
  • 중복 해제(double delete): 소멸자에서 delete를 두 번 호출하여 런타임 에러가 발생할 수 있다.

C++에서 얕은 복사의 문제점 해결

C++에서 얕은 복사의 문제를 해결하려면 깊은 복사를 명시적으로 구현해야 한다.


2. 깊은 복사란?

깊은 복사는 객체와 객체가 참조하는 모든 데이터새로운 메모리 공간에 복사하는 방식이다.

깊은 복사를 사용하면 원본과 복사본이 완전히 독립적으로 동작하며, 서로 영향을 미치지 않는다.

C++에서의 깊은 복사

C++에서는 깊은 복사를 구현하려면 복사 생성자대입 연산자를 오버로드해야 한다

#include <iostream>
using namespace std;

class Deep {
public:
    int* data;
    Deep(int value) {
        data = new int(value); // 동적 메모리 할당
    }
    Deep(const Deep& other) { // 깊은 복사 생성자
        data = new int(*other.data); // 데이터 복사
    }
    ~Deep() {
        delete data; // 동적 메모리 해제
    }
};

int main() {
    Deep obj1(10);
    Deep obj2 = obj1; // 깊은 복사 발생

    cout << "obj1 data: " << *obj1.data << endl; // 출력: 10
    cout << "obj2 data: " << *obj2.data << endl; // 출력: 10

    *obj2.data = 20; // obj2를 통해 데이터 변경
    cout << "obj1 data: " << *obj1.data << endl; // 출력: 10 (독립적임)
    return 0;
}

  • obj1obj2각각 독립적인 메모리 공간을 가진다.
  • 복사본(obj2)이 데이터를 변경해도, 원본(obj1)에는 영향을 미치지 않는다.

Python에서의 얕은 복사

Python에서는 copy.copy()를 사용하면 얕은 복사가 수행된다.

리스트, 딕셔너리와 같은 가변 객체의 내부 참조 데이터는 공유되기 때문에, 원본과 복사본이 서로 영향을 미친다.

import copy

original = [1, [2, 3], 4]
shallow_copy = copy.copy(original)  # 얕은 복사

print("원본:", original)  # 출력: [1, [2, 3], 4]
shallow_copy[1][0] = 99  # 내부 리스트 수정

print("얕은 복사 후:", shallow_copy)  # 출력: [1, [99, 3], 4]
print("원본:", original)  # 출력: [1, [99, 3], 4]
  • 내부 리스트 [2, 3]는 원본과 복사본이 같은 메모리 주소를 공유한다.
  • 복사본에서 내부 리스트를 수정하면 원본에도 영향을 준다.

  • 내부 리스트 [2, 3]는 원본과 복사본이 같은 메모리 주소를 공유한다.
  • 복사본에서 내부 리스트를 수정하면 원본에도 영향을 준다.

Python에서의 깊은 복사

Python에서는 copy.deepcopy()를 사용하여 깊은 복사를 수행할 수 있다.

이 함수는 객체와 모든 참조 데이터를 재귀적으로 복사하여, 원본과 복사본이 완전히 독립적으로 동작하게 만든다.

import copy

original = [1, [2, 3], 4]
deep_copy = copy.deepcopy(original)  # 깊은 복사

print("원본:", original)  # 출력: [1, [2, 3], 4]
deep_copy[1][0] = 99  # 내부 리스트 수정

print("깊은 복사 후:", deep_copy)  # 출력: [1, [99, 3], 4]
print("원본:", original)  # 출력: [1, [2, 3], 4]

  • 복사본은 원본과 완전히 독립적이다.
  • 내부 리스트를 수정해도 원본에는 영향을 미치지 않는다

C++와 Python 비교

특징C++ 얕은 복사Python 얕은 복사C++ 깊은 복사Python 깊은 복사
구현기본 복사 생성자와 대입 연산자 사용copy.copy() 사용복사 생성자와 대입 연산자 오버로드 필요copy.deepcopy() 사용
내부 데이터 공유내부 포인터 공유내부 참조 객체 공유내부 데이터까지 완전 복사내부 데이터까지 완전 복사
메모리 관리수동으로 delete 필요가비지 컬렉터가 자동 관리수동으로 메모리 해제 필요가비지 컬렉터가 자동 관리

마무리하며

C++는 메모리 관리가 필요하며, Python은 자동으로 처리된다는 점에서 복사의 구현과 동작에 차이가 있다.

Python에서는 실무에서 copy 모듈을 적극적으로 활용하여 객체 복사를 처리할 수 있다.

profile
Onward, Always Upward - 기록은 성장의 증거

0개의 댓글