프로그래밍C++ 개발자

복사 생성자와 복사 대입 연산자는 무엇입니까? 동적 메모리를 가진 객체를 복사할 때 오류를 피하려면 어떻게 해야 합니까?

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

답변

복사 생성자복사 대입 연산자는 리소스(예: 동적 메모리)를 소유한 객체와 작업하는 데 필요합니다. 기본적으로 컴파일러는 필드-필드 복사를 생성하는데, 이는 원시 포인터에 대해 안전하지 않습니다:

class Buffer { public: Buffer(size_t size) { data = new int[size]; this->size = size; } ~Buffer() { delete[] data; } // 올바른 복사 생성자 구현 Buffer(const Buffer& other) : size(other.size) { data = new int[size]; std::copy(other.data, other.data + size, 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; } private: int* data; size_t size; };

그렇지 않으면 두 객체를 복사할 때 하나는 메모리를 해제하고 다른 하나는 dangling 포인터를 남기게 됩니다 (double free 또는 use after free).

함정 질문

복사 생성자만 명시적으로 선언하고 대입 연산자는 선언하지 않으면 어떻게 됩니까? 언제 필요하고 언제 필요하지 않습니까?

답변: 복사 생성자만 선언하고 대입 연산자는 선언하지 않으면, 컴파일러는 기본 대입 연산자(비트 복사)를 생성하는데, 이는 객체가 동적 리소스를 포함할 경우 위험합니다. 즉, 동일한 포인터를 두 번 해제하게 됩니다.

메모리 관리를 수행할 경우 둘 다 구현해야 합니다: 복사 생성자와 대입 연산자를 구현하여 복사 오류/메모리 누수를 피해야 합니다.

주제에 대한 미숙지로 인한 실제 오류 사례


이야기

미디어 서버에서 버퍼 객체를 복사할 때 복사 생성자를 사용했지만 대입 연산자를 잊어버렸습니다. 하나의 버퍼를 다른 버퍼에 할당할 때 객체의 해제에서 이중 해제가 발생했습니다. 오류는 스트레스 테스트 중에 나타났습니다.


이야기

물류 프로젝트에서 기본 대입 연산자가 좌표 배열에 대한 포인터가 포함된 구조체를 복사했습니다. 하나의 객체를 삭제한 후, 두 번째 객체가 해제된 메모리에 접근하여 세그멘테이션 오류를 발생시켰습니다.


이야기

그래픽 리소스 프로젝트 중에 스레드 간에 객체를 전달할 때 복사 생성자를 구현하는 것을 잊어버렸습니다. 값에 의한 전달은 얕은 복사를 초래하여, 다른 스레드에서 객체를 변경할 때 데이터 손상 및 프로그램 충돌이 발생했습니다.