WinAPI Core클래스 / Singletone (1)

CJB_ny·2022년 8월 24일
0

WinAPI

목록 보기
7/79
post-thumbnail

싱글톤 패턴

객체의 생성을 하나로 제한

언제어디서든 쉽게 접근이 가능해야함.

extern? => ㄴㄴ.

다른데서도 객체를 만들 수 있다. -> 방지를 못함.

'강제성'이 없음.

그래서 방법중 하나가 '생성자'를 숨기는 것이다.

이렇게하면 외부에서 객체를 못 만든다.

그런데 문제가 extern선언도 할 수 없다.

그래서 CCore의 멤버함수로만 호출이 가능하도록 해주는 함수제공해준다.

근데 이것도 말이 안되는게 멤버함수는 객체가 있어야한다.

객체가 없어도 호출할 수 있는 멤버 함수를 만들자

어? 이거 배웠다 => static키워드

static / 정적멤버 함수❗❗❗

객체가 있어도 호출이 가능하고

객체가 없어도 호출이 가능함.

해당 클래스에 딱 붙어있는 애라

static 멤버함수는 static 붙은 멤버 변수만 사용할 수 있다.

왜? 라는 궁금증이 나오면 객체를 여러개를 만들 경우를 생각해봐라.

왜?? -> 객체를 여러개 만들면 어떻게할 껀데?

애초에 객체없이 호출이 가능하다는 말이

정적 멤버 함수는 'this'가 없다는 것이다.

객체를 통해서 정적 멤버함수를 호출해도 아무 의미가 없다.

즉, => 멤버 접근 불가능.

다 같은 말이다.

정적

경우

정적변수는 어느 메모리를 사용하노? => '데이터 영역'

1) 함수 안에 있을 경우

함수를 통해서만 접근 가능.

2) 파일 안에 있을 경우

마찬가지로 데이터 영역쓰는데 해당 파일에서만 접근이 가능함.
다른 파일에서 같은이름으로 있어도 상관없다.
파일안에서만 접근이 가능하기 때문에.

3) 클래스안에 있을 경우

정적 멤버 라고한다.
마찬가지로 데이터 영역쓴다.

클래스가 아무리 많아져도 정적 멤버로써 클래스의 크기도 차지 하지 않고 데이터 영역에 들어감.

클래스의 정적 멤버로써 존재한다.

객체 수랑 상관없음.

클래스 내부에서 다 접근이 가능함.

이런식으로 일반 멤버함수에서도 접근이 가능함.

정정멤버 함수에서 정적 멤버 변수에 접근이 가능한 이유는

둘다 클래스의 '멤버'이기는 하지만 '데이터'영역에 올라가있기 때문에

접근이 가능하지 않겠나?

착각 ㄴㄴ ❗❗

착각하면 안되는게,

정정멤버는 정적 멤버함수에서만 접근 가능한게 아니라,
정적 멤버함수는 정적 멤버밖에 접근 못한다.

동그라미가 객체인데 스택이든, 힙이든 어디든 만들던지 간에

정정멤버는 데이터에 하나만 있다.

그리고 해당 클래스를 지원해주는 멤버 에서만 접근이 가능함.

그래서 '정적 멤버 함수'도 정적인데 어떻게 정적멤버에 접근이 가능하지?

=> 객체안에 들어있는게 아니라 데이터 영역에 들어있기 때문에...

'정적 멤버 함수'가 일반 멤버에 접근 못하는것은

말그대로 '클래스' 객체에 소속된게 아니라 데이터 영역에 올라가있기 때문에

주의 ❗

정적 멤버 변수는 항상 선언을 하고 초기화를 해주어야한다.

이렇게

(근데 C++11문법으로 클래스 내부에서 초기화 가능하지 않나..? => 안되네)

만약 초기화 안해주면 링크 오류가 난다.

정적 멤버 변수는 데이터영역에 올라갈 것이기 때문에 반드시 초기화를 해주어야 한다.


질문 ❗❗❗

질문 1

데이터영역에는 초기화를 안했을 경우의 데이터도 올라갈 수 있고

초기화를 했을때 올라가는 영역이 있지 않나?

https://velog.io/@starkshn/CPPRO%EB%B3%80%EC%88%98%EC%99%80-%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0

초기화 한 경우 Data영역

초기화 하지 않으면 BSS영역

그렇다면 초기화 하지 않고 BSS영역에 올라면 되는거 아닌가..??

답변

static 멤버 변수는 모든 객체가 '공유'해야 하므로 프로그램 전체 영역에서 메모리 유지가 되야 한다. 따라서 반드시 전역 범위에서 정의 및 초기화를 해주어야 한다.

그래서

'전역 범위'에서 자료형이름 클래스이름::static변수이름 = 초기화할값 형식으로 초기화 해준다.

질문 2

정적 멤버 변수의 경우 왜 C++11문법으로 초기화가 되지 않나요?

=> 씨발 빙시야 객체만들때 마다 '정적'인 변수를 초기화 할래?

OK.

다시 돌아와서

생성자를 private으로 막았기 때문에 외부에서는 더이상

생성자를 호출하지 못한다 => 객체를 못 만든다.

그렇다는 것은 private멤버는 본인 클래스 내부에서는 접근이 가능하니까

CCore라는 객체를 내부에서 스스로 만들어서 반환을 해주자~

그러면 '싱글톤'이 되지 않을까? 해서 아이디어를 냈지만

그렇게 할려고 하니까

멤버 함수는 애초에 '객체'가 있어야 되는데

객체없이 객체를 호출해서 만들어서 준다??

이거 안되네?

그러니까 GetInstance가 일반 멤버함수가 아니라

객체없이 호출이 가능한 정적멤버 함수가 되어야한다.

근데 이렇게하면

호출할때마다 객체 만들어짐.

정적변수 특징 ❗

정적 변수는 초기화가 딱 한번 발생한다 ❗❗❗

그래서 최초로 호출된 경우

new CCore를 통해서 pCore에다가 주소를 받아 두는데

pCore를 정적멤버 변수로 만들어준다.

그러면 초기화가 '딱 한번만' 발생을 한다.

그런데 pCore가 nullptr이라는 말이 '최초로' 호출된 경우이다.

이거 조금 수정해서

이렇게

다시 이렇게.

해제 ❗

우리가 동적할당 했기 때문에 delete도 해주어야한다.

그런데 pCore의 경우 GetInstance만들 통해 접근이 가능함.

(이게 static장점임)

어떻게 Releas에서 해제를 할껀데?

이렇게 하면 돼지년아!

근데 이렇게 하면 '문제'가 있다.

심각한 문제 ❗❗❗

지금 GetInstance를 통해 정적 멤버 포인터 변수(유일한)

pCore를 동적할당 받아서 사용이 가능한 상태기이는 하다.

어디에서든 GetInstance를 호출을 하면 유일한 pCore가 반환되어 올 것이다.

그리고 Release를 해주면 delete p를 하여

주소 값변수명값(데이터 == 가르키는 값)
0x1000pCorenew를 통해 받은 주소값 0x2000

이상태 인데 Release함수안에서

delete p를 한다는 말은 GetInstance를 통해 동적할당 받은

주소 즉, pCore의 값 부분을 날려버리는 것이다.

pCore의 값 부분에는 여전히 접근이 가능하다.

즉 0x2000번에는 delete하여 접근이 가능함.

그런데 0x2000번에는 '쓰레기 값'이 들어있는 상태임.

그렇다면 내가 GetInstance를 통해 주소를 할당받고 다 사용한거 같아서 Release했을 때

시발 다시 겜할래 해서 GetInstance를 하면

어떻게 될까? 그대로 pCore를 동적할당 받지 않고 바로 반환받음(if문에 안걸리고)

그런데 if 문에 당연히 안걸리고 0x2000이 가리키는 곳은 쓰레기 값이 들어있는 곳을 받게됨

=> 에러남. 접근 머시기.

그래서 이게 정상적으로 돌아가는 싱글톤이 아니다.

그래서 pCore를 GetInstance의 정적멤버로 선언해둘게 아니라

클래스의 정적 멤버로 선언해두는게 좋지 않나?

GetInstance, Release 둘다 접근이 가능하게 할려면...

이렇게.

(초기화는 .cpp파일에서)

요로코롬.

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글