기본 패턴
cpp
class Buffer {
public:
Buffer(const Buffer& other);
Buffer& operator=(const Buffer& other);
~Buffer();
};설명
- C++ 클래스는 특별한 멤버 함수들이 자동 생성될 수 있는데, 그중 복사 생성자, 복사 대입 연산자, 소멸자는 자원 소유와 직접 연결됩니다.
- 단순 값만 담는 클래스라면 컴파일러 기본 동작이 충분한 경우가 많지만, 동적 메모리나 파일 핸들처럼 "직접 정리해야 하는 자원"을 소유하면 상황이 달라집니다.
- 이때 얕은 복사가 일어나면 여러 객체가 같은 자원을 동시에 가리키고, 이중 해제나 의도치 않은 공유 상태가 생길 수 있습니다.
- 그래서 전통적으로는 rule of three, 현대 C++에서는 move까지 포함한 rule of five라는 관점으로 special member functions를 함께 생각합니다.
- 결국 핵심 질문은 "이 클래스가 무엇을 소유하는가, 복사되면 그 소유권을 어떻게 해석할 것인가"입니다.
짧은 예제
cpp
#include <algorithm>
class Buffer {
public:
explicit Buffer(int size) : size(size), data(new int[size]{}) {}
Buffer(const Buffer& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
}
~Buffer() {
delete[] data;
}
private:
int size;
int* data;
};빠른 정리
| 항목 | 설명 |
|---|---|
| 복사 생성자 | 새 객체를 기존 객체로부터 복사 생성 |
| 복사 대입 | 이미 존재하는 객체에 값을 복사 |
| 소멸자 | 객체 수명 종료 시 자원 정리 |
| rule of three/five | 자원 소유 클래스에서 special member를 함께 고려 |
| 핵심 판단 | 얕은 복사가 안전한가, 깊은 복사가 필요한가 |
주의할 점
raw pointer를 직접 소유하는 클래스에서 복사 의미를 명시하지 않으면 기본 얕은 복사가 문제를 만들 수 있습니다. 이런 설계는 스마트 포인터나 표준 컨테이너로 대체할 수 있는지도 함께 보는 편이 좋습니다.