[C++] 소멸자

cheon2308
|2023. 11. 29. 14:14
728x90

황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!

https://search.shopping.naver.com/book/catalog/32436115747

 

C++ Programming : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

 

소멸자

  • 객체가 소멸되면 객체 메모리는 시스템으로 반환
  • 소멸자(destructor)는 객체가 소멸되는 시점에서 자동으로 호출되는 클래스의 멤버 함수
class Circle{
    Circle();
    Circle(int r);
    // .....
    ~Circle();
};

Circle::~Circle() {
    .....
}

 

특징
  1. 소멸자의 목적은 객체가 사라질 때 필요한 마무리 작업을 위함이다.
    • 동적으로 할방받은 메모리를 운영체제에게 돌려주거나,
    • 열어 놓은 파일을 저장하고 닫거나
    • 연결된 네트워크를 해제하는 등의 작업을 하기 위함
  2. 소멸자의 이름은 클래스 이름 앞에 ~를 붙인다.
    • Circle 클래스의 소멸자 이름은 ~Circle()이며, 소멸자는 다음과 같이 작성
    • Circle::~Circle() { ... }
  3. 소멸자는 리턴 타입이 없으며 어떤 값도 리턴해서도 안 된다.
    • 소멸자는 생성자와 같이 리턴 타입 없이 선언되며 어떤 값도 리턴해서는 안됨
  4. 소멸자는 오직 한 개만 존재하며 매개 변수를 가지지 않음
    • 생성자와 달리 한 클래스에 한 개만 존재하며 매개 변수를 가지지 않는다.
  5. 소멸자가 선언되어 있지 않으면 기본 소멸자(default destructor)가 자동으로 생성
    • 생성자와 마찬가지로 소멸자가 없는 클래스는 컴파일러에 의해 자동으로 기본 소멸자가 주어지며, 이 때 기본 소멸자는 단순 리턴만 함

 

실행
  • 클래스에 소멸자를 추가하고, 소멸자가 실행되면 메시지를 출력하도록 해보자.
#include <iostream> 
using namespace std; 

class Circle {
public:
	int radius;
	Circle(); 
	Circle(int r); 
	~Circle(); // 소멸자
	double getArea(); 
};

Circle::Circle() {
	radius = 1;
	cout << "반지름 " << radius << " 원 생성" << endl;
}

Circle::Circle(int r) {
	radius = r;
	cout << "반지름 " << radius << " 원 생성" << endl;
}

Circle::~Circle() {
	cout << "반지름 " << radius << " 원 소멸" << endl;
}

double Circle::getArea() {
	return 3.14*radius*radius;
}

int main() {
	Circle donu;
	Circle pizza(30); 
	return 0;
}

/*
반지름 1 원 생성
반지름 30 원 생성
반지름 30 원 소멸
반지름 1 원 소멸
*/
  • main()의 스택에 donu, pizza의 순서로 객체 생성 후 return 0문이 실행
  • 생성 반대 순으로 pizza, donu 객체가 소멸

생성자/ 소멸자 실행 순서

  • 함수 내에서 선언된 객체 => 지역 객체(local object)
  • 함수 바깥에 선언된 객체 => 전역 객체(global object)

지역 객체함수가 실행될 때 생성, 종료할 때 소멸

전역 객체프로그램 로딩시 생성, main()이 종료한 뒤 프로그램 메모리가 사라질 때 소멸

둘다 생성된 순서의 반대순으로 소멸된다.

 

#include <iostream> 
using namespace std; 

class Circle {
public:
	int radius;
	Circle(); 
	Circle(int r);
	~Circle(); 
	double getArea();
};

Circle::Circle() {
	radius = 1;
	cout << "반지름 " << radius << " 원 생성" << endl;
}

Circle::Circle(int r) {
	radius = r;
	cout << "반지름 " << radius << " 원 생성" << endl;
}

Circle::~Circle() {
	cout << "반지름 " << radius << " 원 소멸" << endl;
}

double Circle::getArea() {
	return 3.14*radius*radius;
}

Circle globalDonut(1000);
Circle globalPizza(2000);

void f() {
	Circle fDonut(100);
	Circle fPizza(200);
}

int main() {
	Circle mainDonut;
	Circle mainPizza(30);
	f();
}

위 코드의 생성과 소멸 과정

 


힙 객체

  • 위와 반대로 힙 객체는 자동으로 삭제되지 않는다 => 스마트 포인터를 사용하지 않은 경우!!
  • 따라서, 객체 포인터에 대해 delete를 명시적으로 호출하고 메모리를 해제 해야 한다.
  • 기본 생성자의 경우 stack에 생성됨
// 명시적 소멸자 호출 예제
int main() {
    Person* pPtr1 = new Person("jin", 27);
    Person* pPtr2 = new Person("chul", 26);
    
    cout << "jin의 나이: " << pPtr1->getAge() << endl;
    delete pPtr1;	// pPtr1이 가리키는 메모리 공간(힙)을 해제한다.
   	pPtr1 = nullptr;	// 잘못된 잘못을 막고자 널을 대입
    
    return 0;
}
// pPtr2에 대해선 delete를 통해 가리키는 메모리 공간을 해제하지 않았다.

 

  • 위와 같이 포인터가 가리키는 공간을 해제하지 않고 남겨두면 안 된다. 
  • 항상 delete or delete[]를 호출해서 동적으로 할당된 메모리를 해제해야 한다.
  • 이러한 실수를 막기 위해서는 스마트 포인터를 사용하는 방법이 있다.
728x90