프로그래밍C++ 개발자

얕은 복사와 깊은 복사의 차이를 동적 메모리를 사용하는 컨테이너의 예로 설명해 주세요. 깊은 복사를 어떻게 올바르게 구현하나요?

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

답변.

얕은 복사(Shallow copy)는 클래스의 멤버 값, 포인터를 포함하여 복사하지만, 이 포인터들이 가리키는 데이터는 복사하지 않습니다. 깊은 복사(Deep copy)는 포인터들이 가리키는 데이터의 새로운 복사본을 생성하여 메모리의 공유 소유와 이중 해제를 방지합니다.

예:

class Buffer { public: Buffer(size_t size) : size(size), data(new int[size]) {} // 얕은 복사(잘못됨) Buffer(const Buffer& other) : size(other.size), data(other.data) {} // 깊은 복사(올바름) Buffer& operator=(const Buffer& other) { if (this != &other) { delete[] data; size = other.size; data = new int[size]; std::copy(other.data, other.data + size, data); } return *this; } ~Buffer() { delete[] data; } private: size_t size; int* data; };

트릭 질문.

클래스가 동적 배열을 가리키는 포인터를 포함하고 있다면, 왜 기본 복사 생성자와 할당 연산자를 그대로 복사하는 것으로 충분하지 않은가요?

올바른 답변:

기본 복사는 얕은 복사를 구현합니다. 두 개의 객체가 동일한 배열을 가리키게 되며, 삭제될 때 동일한 메모리를 두 번 해제하려고 시도하여(이중 해제) 프로그램이 충돌할 수 있습니다.

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


이야기 대규모 서버 애플리케이션에서 동적 픽셀 버퍼를 관리하는 자체 Image 클래스를 구현했습니다. 개발자들은 깊은 복사를 구현하지 않았고, Image 객체를 스레드 간에 값으로 전달할 때 메모리의 이중 해제가 발생하여 며칠에 한 번씩 시스템 충돌이 발생했습니다.


이야기 학생 프로젝트에서 동적으로 할당된 셀 배열을 가리키는 포인터를 포함한 Field 컨테이너를 사용했습니다. 배열 크기를 변경할 때 복사 생성자가 포인터만 복사하여 두 컨테이너가 동일한 메모리 영역을 사용하게 되었고, 이로 인해 일관성이 없는 데이터와 찾기 어려운 버그가 발생했습니다.


이야기 구식 C++ 그래픽 엔진 코드에서 자신의 소멸자와 할당 연산자를 구현하지 않은 Texture 클래스가 존재하여, 복사 및 임시 텍스처 할당 시 메모리 누수(memory leak)가 발생했습니다.