클래스가 다음 중 하나를 정의하는 경우
(1) 소멸자 (2) 복사 생성자 (3) 복사 대입 연산자 세 가지를 함께 정의해야 한다는 규칙이다.
이 규칙을 통해 리소스 관리가 더 안전하고 예측 가능해지며, 메모리 누수와 같은 문제를 방지할 수 있다. 물론 일관성 유지는 덤이다.
이 세가지에 대해 잘 모르는 분들을 위해 설명을 덧붙여본다.
객체가 삭제될 때 자동으로 호출된다.
소멸자는 주로 객체가 사용하던 동적 메모리나 파일 핸들 같은 자원을 정리하고 반환하는 역할을 한다.
→ 프로그램이 메모리 누수 없이 효율적으로 자원을 관리할 수 있다.
현재 String 클래스를 작성해보는 실습을 만들고 있어서 예제로 가져와봤다. 아래 예시와 같이 보통 동적 메모리를 해제하는 로직을 추가해준다.
class String {
private:
char* str;
public:
String (int size) {
// 동적 메모리 할당
str = new char[size];
}
~String () {
// 동적 메모리 해제
delete[] str;
}
};
객체를 복사하여 새로운 객체를 만들 때 호출되는 생성자이다.
객체가 다른 객체를 통해 초기화될 때(복사할 때) 자원이 안전하고 올바르게 복사되도록 도와준다.
기본적으로 C++는 복사 생성자를 자동으로 만들어주지만, 동적 메모리나 특정 자원을 사용하는 경우, 복사 생성자를 직접 정의해 줘야한다.
내부에서는 다음과 같이 메모리 할당 후 데이터를 복사해주면된다. 이렇게 하면 단순히 포인터 값만 복사하는 것이아니므로 얕은 복사 문제를 일으키지 않는다.
class String {
private:
char* str;
public:
String (const Srting& origin) {
str = new char[origin.length() + 1];
strcpy(str, origin.str);
}
};
이미 존재하는 객체에 다른 객체의 값을 복사할 때 호출되는 연산자이다.
아래 예시와 같이 기존 자원을 해제하고 값을 복사해주어야한다.
class String {
private:
char* str;
public:
String& operator=(const Srting& origin) {
// 본인 복사 방지
if (this == &other) return *this
delete[] str;
str = new char[origin.length() + 1];
strcpy(str, origin.str);
return *this;
}
};
특별하게 어려운 내용은 없으나, C++에서 클래스 생성자 관련하여 꼭 알아야할 점이라고 생각해서 포스팅한다.