프로그래밍C++ 개발자

C++에서 얕은 복사(shallow copy)와 깊은 복사(deep copy)의 차이점은 무엇인가요? 깊은 복사를 스스로 구현해야 하는 상황은 언제이며, 올바르게 구현하는 방법은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

얕은 복사(shallow copy) – 객체의 필드 값만 복사하며, 포인터를 포함하지만 동적으로 할당된 메모리는 중복하지 않습니다. 결과적으로 두 객체는 동일한 메모리 영역을 가리킵니다. 이는 데이터 변경이나 메모리 해제 시 오류를 발생시킬 수 있습니다.

깊은 복사(deep copy) – 객체가 참조하는 모든 자원의 완전한 복사본을 만들어 각 객체가 자기 데이터 사본을 소유하도록 합니다.

깊은 복사가 필요한 경우:

  • 객체가 동적으로 할당된 메모리를 소유하는 경우.
  • 하나의 객체 내용 변경이 다른 객체에 영향을 미치지 않아야 할 때.

깊은 복사 구현 예시:

class ArrayHolder { public: ArrayHolder(size_t size) : sz(size), data(new int[size]) {} ~ArrayHolder() { delete[] data; } // 깊은 복사 생성자 ArrayHolder(const ArrayHolder& other) : sz(other.sz), data(new int[other.sz]) { std::copy(other.data, other.data + other.sz, data); } // 깊은 복사 할당 연산자 ArrayHolder& operator=(const ArrayHolder& other) { if (this != &other) { delete[] data; sz = other.sz; data = new int[sz]; std::copy(other.data, other.data + sz, data); } return *this; } private: size_t sz; int* data; };

함정 질문.

질문: 복사 생성자에서 단순히 포인터 값을 복사하면 제대로 작동할까요?

답변: 아니요, 이것은 두 객체가 파괴될 때 메모리 이중 해제(double free)를 초래합니다. 자원 관리를 올바르게 하기 위해 깊은 복사를 구현해야 합니다.

주제의 미세한 차이에 대한 실제 오류 사례.


이야기

한 프로젝트에서 모듈 간 배열을 전송하기 위해 기본 복사 생성자가 포인터만 복사하도록 설정된 클래스 객체를 사용했습니다(얕은 복사). 결과적으로 임시 객체가 범위를 벗어난 후 배열이 파괴되고 기본 객체는 "중단된" 포인터를 남겨 두어 정의되지 않은 동작과 애플리케이션 충돌을 초래했습니다.


이야기

이미지 작업을 위한 라이브러리에서 동적으로 할당된 버퍼를 포함하는 객체가 여러 번 복사되었습니다. 깊은 복사가 없어서 한 객체의 메모리가 해제된 후 다른 객체가 해제된 영역에 접근하였습니다. 데이터 손상과 객체 삭제 시 크래시가 발생했습니다.


이야기

구식 코드를 현대 표준과 통합 할 때, 구식 클래스에는 복사 생성자와 할당 연산자가 구현되지 않았습니다. 이러한 클래스를 표준 라이브러리 컨테이너와 함께 사용하면 컨테이너가 객체를 얕게 복사하여 예기치 않은 오류가 발생했습니다.