티스토리 뷰
* class 구조
1. 생성자함수
2. 복사생성자함수
3. 소멸자 함수
4. 대입연산자 함수
* 소멸자
c++은 java나 c#과 달리 플랫폼에서 개체들을 관리하지 않는다. 따라서 c++에서는 생성한 개체의 소멸에 관한 책임을 개발자가 져야한다.
소멸자도 생성자처럼 직접 호출하지 않고 delete 연산자를 사용해야한다. 또한 소멸자는 생성자와 다르게 중복 정의할 수 없다. 소멸자도 개발자가 정의하지 않으면 컴파일러에 의해 디폴트 소멸자가 만들어진다. 하지만 개체 내부에서 동적으로 다른 개체를 생성하였다면 소멸자를 정의하여 동적으로 만든 개체를 소멸해야 한다.
* 소멸자함수를 쓰는 이유
동적메모리를 할당 하고 난뒤 쓰레기값이 남게된다. 프로세스를 다 돌리고 난 후 쓰레기 메모리 값을 소멸해주지 않으면 다른 프로그램을 프로세스 할 때마다 메모리들이 남아 메모리 공간을 차지하게 된다. 소멸자 함수를 쓰는 이유는 메모리 낭비를 줄이기 위해서라고 할 수 있다.
* 소멸자 함수 특징
1. 객체 소멸시 자동 호출되어지는 함수. 만약, 동적 할당뒤에 메모리 할당 해제 안 해준 경우 소멸자 함수 호출 불가능
2. 생김새 : 틸드(~)가 클래스명 앞에 있으면 소멸자 함수
~클래스명( ){ }
3. 매개변수를 선언 할 수 없다.
4. 오버로딩이 불가능하다. 매개변수가 없기 때문에 클래스 통틀어서 함수가 오직 하나이다.
5. const member function으로 만들수 없다.
6. 객체의 잔여메모리를 깨끗하게 정리하는 역할을 함(개발자가 직접 설정해줘야함)
7. 역할 : 동적 메모리 필드 제거
* 소멸자 함수 이해하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 |
#include <iostream>
#include <iomanip>
using namespace std;
class A {
int *p;
public:
//생성자
A(int i = 0) {
p = new int;//동적 메모리 할당
*p = i;//포인터가 잡고 있는 주소에 i의 값이 들어간다
}
//복사생성자가 생략되어 있음
/*A(const A&aa) {
p = aa.p;
//포인터의 주소값 복사
}*/
~A() {
delete p;//메모리 모두 소멸시키기
}
int getP() { return *p; }
};
void main() {
A aa(10);
A bb(aa);//복사생성자 호출
cout << bb.getP() << endl;
//main은 stack 영역에 저장된다.
//스택은 마지막에 들어온 것이 제일 처음 사라진다(후입선출,LIFO)
//결국 bb, aa순으로 사라짐
//이때, bb와 aa는 똑같은 10의 주소를 가리키고 있는데, bb가 가리키는 10이 사라져서
//aa 메모리를 삭제할 수 없어진다. >>런타임 오류가 뜬다.
} |
cs |
* 위의 소멸자 함수 오류코드를 고쳐보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 |
#include <iostream>
#include <iomanip>
using namespace std;
class A {
int *p;
public:
//생성자
A(int i = 0) {
p = new int;//aa 포인터
*p = i;//포인터가 가리키는 주소에 i의 값을 넣어라
}
//복사생성자//깊은 복사
A(const A&aa) {
p = new int;//bb 포인터
*p = *aa.p;//포인터가 가리키는 값에 매개변수 aa 넣어라
}
//소멸자 함수
~A() {
delete p;//메모리 모두 소멸시키기
}
int getP() { return *p; }
};
void main() {
A aa(10);
A bb(aa);//복사생성자 호출
cout << bb.getP() << endl;
//main은 stack 영역에 저장된다.
//스택은 후입선출(LIFO)
//결국 bb , aa순으로 사라짐
//위에서는, bb와 aa는 똑같은 10을 넣은 주소를 가리키고 있어서 런타임오류가 떴었는데
//그 오류를 안 뜨게 하기위해선 bb의 포인터가 주소를 가리키는 것이 아닌
//그 주소에 들어있는 값을 가리키게 하면 된다.
} |
cs |
* 소멸자 함수 응용하기
1. 다음 코드를 보고 출력되는 문구가 총 몇줄인지 맞춰보시오.
2. 어떤 문구가 순서대로 출력 되는지 맞춰보시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 |
#include <iostream>
#include <iomanip>
using namespace std;
class A {
public :
A() { cout << "생성자 함수" << endl; }
~A() { cout << "소멸자 함수" << endl; }
A(const A&aa) { cout << "복사생성자함수" << endl; }
void setObject(A aa) {}
A getObject() { A aa; return aa; }
};
void main() {
A aa;//1번
A bb(aa);//2번
A cc = bb;//3번
aa.setObject(bb);//4번
bb.setObject(cc);//5번
cc.setObject(aa);//6번
aa.getObject();//7번
bb.getObject();//8번
cc.getObject();//9
} |
cs |
* 풀이
1번 : aa 객체 선언, 생성자로 감, main(stack 영역에 저장됨)이 끝날때 까지 객체가 존재하기에 소멸자함수는 main이 끝난다음 호출됨
2번 : bb 객체 선언, 복사 생성자로 감, main이 끝난 다음 소멸자 함수 호출됨
3번 : cc 객체 선언, 복사 생성자로 감, main이 끝난 다음 소멸자 함수 호출됨
4번, 5번, 6번 : bb를 인자로 갖는 aa 객체, 복사 생성자 호출, bb인자는 매개변수 aa가 받음. class 영역 에서 함수 기능이 종료됐기 때문에 set 함수 종료뒤 소멸자 함수 호출
7번, 8번, 9번 : get 함수에서 맨 처음 aa 객체 선언(이때 main의 aa 객체와는 구별된다)하여 생성자함수 호출, 메소드에서 return을 하면 무조건 복사생성자를 호출한다. get 함수가 끝나면 생성자 함수, 복사생성자 함수 2가지 기능이 끝난 것이기에 소멸함수도 2번 호출 된다.
1번, 2번, 3번 : main 함수가 종료되면 1번, 2번, 3번 객체선언한 기능이 사라지므로 소멸자 함수 3번 호출
* 출력 결과
'Programming > C++' 카테고리의 다른 글
[c++]has~a 관계를 이용한 사람수 제한없는 성적프로그램 (0) | 2018.03.08 |
---|---|
[c++]const (0) | 2018.03.08 |
[c++]복사생성자 (0) | 2018.03.07 |
[c++]class, 생성자 (0) | 2018.03.07 |
[C++]동적할당을 이용한 사람수 제한 없는 성적프로그램 (0) | 2018.03.06 |