생성자와 소멸자

 

생성자와 소멸자는 클래스가 언제 생성되고 언제 소멸되는지를 보여준다.

 

스택이냐 힙이냐 종류가 다르면 소멸하는 시기가 다르다.

 

이 포스팅에서는 스택과 힙에 객체를 만들면 어떤 차이가 생기는지 알아본다.

 

자바와 달리 C++ 에서는 스택에 객체를 만들 수 있다. new 키워드를 사용하지 않고 객체를 선언하면 된다.

 

아래의 클래스로 테스트 한다.

 

 

생성자는 오버로드 하는데 매개변수가 없는 MyDog 은 스택의 생성에 사용한다.

 

매개변수가 있는 MyDog 은 힙에 만들 객체에 사용한다.

 

 

MyDog WangWang 을 선언하는 순간에 생성자가 호출된다.

 

MyDog* ptrDoolly 로 new 키워드로 힙영역에 객체가 생성된다.

 

다음 delete 로 힙영역에서 소멸시킨다.

 

결과를 놓고 보면 스택의 소멸자는 더 나중에 호출된다. 이것은 main 함수가 종료하기 전에 지역변수들을 메모리에서 해제하면서 호출된다. 힙영역에 생성한 객체는 뒤에 선언되었음에도 불구하고  delete 명령어로 이미 소멸이 된 상태다.

 

 

만약 delete 를 호출하지 않는다면 아래와 같은 결과를 볼 수 있다. 힙영역의 소멸자는 호출하지 않는다. 이것을 보면 스택의 객체는 main 함수가 종료될 때 소멸을 시키는데 힙영역의 객체는 그 과정을 건너뛰어 버린다. 그냥 프로그램이 종료하면서 함께 사라져버린다. 물론 메모리는 반환되었겠지만 명시적으로 delete 를 사용하는 것이 좋은 방법이다. 메모리가 통째로 버려지는 기분이라 찜찜하다.

 

 

포인터로 멤버에 접근하기

스택에 만든 지역변수 객체는 . 도트연산자로 객체의 멤버에 접근할 수 있다. 한편 힙에 만든 객체는 포인터로 접근해야한다. 간접연산자 * 를 사용하는 C++ 문법에서는 (*포인터).멤버 로 해야한다. 그런데 이게 번거로우니까 포인터->멤버 이 표현으로 대체해버렸다. 갑자기 -> 이게 나오면 헷갈릴 수 있는데 (*포인터). 를 줄인 것이다.

 

객체 변수 자체에는 클래스에 대한 특별한 참조를 가지고 있는데 이는 메모리 주소값과는 다른 것이다. 클래스를 선언한 변수 위에서는 WangWang 도 메모리 주소를 가지고 있지만 그 안에 들어있는 내용은 객체를 참조할 수 있는 정보를 가지고 있다.

 

 

테스트를 하기 위해 public 에 위와 같은 메소드를 만들었다.

 

위에서 (*ptrDoolly).bark는 -> 이것과 같다.

 

 

비주얼 스튜디오에서는 자동완성을 지원한다. 도트연산자 . 를 커밋하면 -> 로 바꿔주는 편리한 기능이 있다.

 

요약

 

생성자와 소멸자를 사용해서 스택과 힙에서 객체의 생성과 소멸이 다르다는 것을 알 수 있었다.

 

C++에서는 delete를 명시적으로 사용하는 습관이 필요하다. 프로그램이 종료되면 힙메모리도 시스템에 반환되지만 그렇게 놔두는 것은 C++에서 좋은 방법이 아니다.

 

포인터가 사용하는 -> 연산자는 실제는 (*포인터).멤버 로 변환된다.

 

 

 

*소스코드

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

#define Line cout <<"\n-----------------------------\n"

class MyDog
{
public:
	MyDog();
	MyDog(string name);
	~MyDog();
	void bark();
private:
	string name = "기본";
	int age;
};

MyDog::MyDog()
{
	cout << " 생성자 호출 : 기본" << endl;
}

MyDog::MyDog(string name)
{
	this->name = name;
	cout << " 생성자 호출 : " << this->name << endl;
	age = 2;
}
MyDog::~MyDog()
{
	cout << " 소멸자 호출 : " << this->name << endl;
}
void MyDog::bark()
{
	cout << "Wang! Wang! ";
	cout << "I am " << this->name << endl;
}

int main()
{
	MyDog WangWang = MyDog("왕왕이");

	MyDog* ptrDoolly = new MyDog(" 둘리");

	Line;
	WangWang.bark();
	ptrDoolly->bark();

	Line;
	cout << " 힙 메모리를 해제합니다\n";
	delete ptrDoolly;
	Line;
	
	return 0;
}

공유하기

facebook twitter kakaoTalk kakaostory naver band