인프런 커뮤니티 질문&답변

작성자 없음

작성자 정보가 삭제된 글입니다.

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진

Input Manager

static 키워드에 대한 의문

21.04.02 00:52 작성

·

768

0

안녕하세요 강의를 들으며 많은 것을 배워가고 있습니다.

static 키워드에 관해 두가지 질문을 드리고 싶습니다.

1.

static 변수는 프로그램의 시작과 함께 데이터 영역에 할당이 된다고 배웠습니다. 의문점은 문득 코드를 살펴보다 static으로 선언된 Input이라는 변수는 인스턴스화 하기 전에 할당되는 변수인데 get으로 _input을 반환한다는게 조금 어색하게 다가왔습니다. 혹시나 하는 마음에 s_instance를 반환하는 Instance 프로퍼티를 가지고 유사하게 실험을 했습니다. static Managers s_instance;에서 static을 없애니 Instance로 선언된 프로퍼티의 get부분에서 s_instance를 static으로 선언하라는 에러가 났습니다.

위의 두 줄과 아래 두 줄이 동일한 매커니즘을 거치는 것 같은데 한쪽은 static이 없고 한쪽은 static이 있어야 하는 상황에 대해서 알고싶습니다.

2. 두번째 질문은 static 메서드와 static 변수는 정확히 어느 시점에서 할당이 되는지 궁금합니다. 구글링을 해보니 "클래스가 메모리에 올라갈때" 라는 다소 추상적인 글을 확인할 수 있었습니다. 이 말이 로딩과정에 일어나는 일이라고 이해해도 되는걸까요? 이에 대해 조금 자세히 설명을 부탁드려도 될까요?

답변 3

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

2021. 04. 02. 02:23

static에 대한 대혼란이 일어나고 있는 것 같네요.
우선 static이 붙은 애들은 class에 없다고 가정하고 분리해서 생각해봅시다.
위와 같은 Managers 설계도가 있을 때,
new Managers를 통해 새로운 객체를 만들면
내부적으로 InputManager가 같이 만들어지게 됩니다.

이제 static 변수를 생각해볼건데,
static이 붙으면 사실 특정 객체랑은 무관하고 class랑 종속적이라 봐야 합니다.

위 상태에서 Managers m = new Managers를 하더라도,
m 객체 내부에 s_instance가 있지는 않습니다.
즉 Managers.s_instance로 접근하도록 Managers 이름은 빌리고 있지만
Managers 객체 하나 하나랑은 무관하다는 것입니다.

어디선가 

이렇게 s_instance 참조에 객체를 만들어줄 수는 있겠죠.


Managers 내부에 정의된 static 함수 또한,
Managers의 이름만 빌리고 있을뿐
Managers 객체 하나 하나랑은 아무 상관이 없습니다.
따라서 위에서 static인 Test 내부에서 _input에 접근하려 하면 에러가 납니다.
왜냐하면 지금까지 우리가 _input. 으로
멤버 함수 내부에서 멤버 변수를 접근하던 행위는,
[멤버 함수를 호출하고 있는 객체의 _input에 접근한다]는 의미이기 때문입니다.

아래와 같이는 가능합니다.

이 의미는 [NoStaticTest가 실행되는 객체의 _input을 꺼내 쓰겠다]는 의미입니다.

반대로 아래와 같이는 안 됩니다.


코드 의미로만 보면 [StaticTest가 실행되는 객체의 _input을 꺼내 쓰겠다]는 의미인데,
애당초  static 함수는 특정 객체랑은 아무런 관계가 없기 때문입니다.


애당초 이렇게 호출조차 안 됩니다.

static은 static끼리 놀아야 하는데

이렇게는 또 사용이 가능합니다.
왜냐하면 s_instance도, StaticTest도 static이기 때문이죠.

한 발짝 더 나아가, 우여곡절 끝에 s_instance 객체를 사용하고 있다면
해당 내용물을 꺼내 쓰는 것은 우리 자유입니다.
따라서 아래와 같이는 가능합니다.

이걸 한 번에 하면 다음과 같습니다.

결국 중요한 것은 static 함수 내부에서는
static 변수만 일차적으로 접근 가능하다는 것인데,
해당 static 변수가 참조 타입이면 그 내용물은 마음대로 꺼내 쓸 수 있다는 것입니다.

돌고 돌아 위 예제에서 Instance를 호출하면 init();을 해서 s_instance를 만들어주고,
그 s_instance를 뱉어주는데, s_instance는 static입니다.

따라서 Input에서도 Instance를 사용 가능한 것이고,
일차적으로 접근이 가능하면 그 다음에 내용물인 _input을 꺼내 쓰는 것은 우리 마음입니다.

바로 _input을 하면 안 되는 이유는, 그렇게 하면
[멤버 함수를 호출하고 있는 객체의 _input에 접근한다]는 의미이기 때문입니다.
다시 강조드리지만 static 함수는 특정 객체랑은 무관합니다.

좀 헷갈리는 내용이긴 한데 당장은 크게 중요하진 않으니
그래도 이해 안 가신다면 구글링 신공으로 더 자료를 검색해보시기 바랍니다.
저도 어느날 깨우침이 왔던 것 같네요.

0

--님의 프로필 이미지

2021. 04. 02. 01:47

답변 감사합니다!

몇 가지 질문을 더 해보려고 합니다.

답변해주신 "static인 Instance에 접근한 다음, 해당 객체가 갖고 있는 _input 멤버를 꺼내 쓰는 것이기에 문제 없습니다." 을 여러번 읽어보고 생각을 해봐도 여전히 드는 의문점이 꼬리에 꼬리를 무는듯합니다. 

static인 Instance에 접근하고 해당 객체가 갖고있는 _input멤버를 꺼내 쓴다는 것은,  static메서드에서 non static 맴버 변수를 사용하면 에러가 발생하는 것 과 유사하다고 생각합니다.  뿐만 아니라 Managers 클래스 외부에서 ~~ = Managers.Instance._input;로 _input을 사용하는 부분이 있다고 했을 때 초기화도 되지 않은 변수를 사용하게 될 문제도 있을거라 생각합니다.

추가로, 답변해주신 "InputManager Input { } 내부에서 그냥 바로 return _input; 을 하면 에러가 나는 이유는,어떤 객체의 _input인지를 모르기 때문입니다." 에서 어떤 객체인지 모른다는 의미를 정확히 모르겠습니다. 

늦은시간 죄송합니다 ㅠㅠ제가 엄청 생각이 꼬여있는 듯 합니다.

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

2021. 04. 02. 01:10

1.

작은 디테일인데 static이 데이터 영역에 할당되는 것은 C++ 기준이고,
사실 C#에서는 managed heap에 올라갑니다.
static은 특정 객체에 종속적이지 않고,
해당 class에 종속적이라고 봐야 합니다.
따라서 static은 static끼리 놀아야 하는데,
static InputManager Input { }이 비-static인 _input을 반환하는 부분이 헷갈리시는 것 같네요.
정답부터 말씀드리자면 Instance도 static이기 때문에 가능합니다.
static인 Instance에 접근한 다음, 해당 객체가 갖고 있는 _input 멤버를 꺼내 쓰는 것이기에 문제 없습니다.

InputManager Input { } 내부에서 그냥 바로 return _input; 을 하면 에러가 나는 이유는,
어떤 객체의 _input인지를 모르기 때문입니다.

2.

네 처음으로 해당 static 클래스가 메모리에 올라갈 때인데요.
일반적으로 new를 해서 static이 딸려서 만들어지는 경우라고 생각할 수 있는데
말로 하면 헷갈리니 직접 실습을 해보시기 바랍니다.
임의의 class를 만들고 (ex. TestClass), 
생성자에 breakpoint를 건 다음
다른 class 내부에서 static TestClass를 사용해보면 됩니다.

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기