LPVOID type은 Microsoft에서 정의한 type으로 Windows Kits 8.1 version의 WTypebase.h에 정의된 바로는

void *LPVOID;

로 정의되어 있다.

고로 LPVOID는 void *와 같은 타입이다.

위의 코드에서 마지막 주석의 이유는 다음과 같다.

stackoverflow.com/questions/2709283/c-delete-static-castvoid-pointer-behavior

 

C++ delete static_cast<void*> (pointer) behavior</void*>

suppose the code does the following: T *pointer = new T(); delete static_cast<void*>(pointer); what is result? Undefined, memory leak, memory is deleted?</void*>

stackoverflow.com

내용을 요약하면 C++ 표준에서는 void * 타입을 직접 delete하면 미정의 동작으로 직행한다.

그 이유는 void *는 간접 참조를 할 수 없기 때문이다.

간접 참조란 C/C++에서 포인터가 가리키는 메모리 주소의 값을 획득하는 것을 말한다.

void *이 간접 참조를 할 수 없는 이유는 시스템 마다 자료형에 차이가 나서이다.
(32비트 컴퓨터에서의 long은 4바이트, 64비트 컴퓨터에서의 long 타입은 8바이트)

컴파일러가 얼마나 많은 바이트를 읽어야 할지 모르기 때문에 void *는 간접 참조가 불가능하다.

마찬가지로 void *는 가리키는 메모리 주소에서 필요한 객체에 할당된 메모리 크기를 알 수 없다.

그러므로 void *를 직접 delete 할 수 없다.

 

void * 타입의 delete를 위해서는 casting을 하거나, void *가 아닌 공통의 Interface 또는 class 타입으로 바꾸는게 좋다.

1. Windows에서 명령 프롬포트(cmd)를 호출해보자.

 

2. vcpkg 명령어를 실행해보자.

명령어가 수행되지 않는다.

 

3. vcpkg가 설치된 폴더 경로에서 실행해보자.

명령어가 먹힌다.

 

4. 환경변수에 vcpkg가 설치된 경로를 등록해보자.

시스템 환경 변수 편집 검색 후 클릭

 

환경 변수 버튼 클릭

 

시스템 변수 Path 찾아서 편집 클릭

 

vcpkg가 설치된 폴더에서 전체 경로 복사

 

복사한 경로를 환경 변수 편집 대화상자에서 새로 만들기 후 붙여넣기

 

5. 명령 프롬포트(cmd) 창을 닫았다가 꼭 다시 열어서 vcpkg 명령어를 쳐보자. (경로 무관)

설치 경로가 아니어도 명령어가 수행되는 것을 확인할 수 있다.

 

6. 결론

JAVA 설치에서 꼭 필요한 환경 변수의 비밀.

OS가 명령어 수행을 위해 설치나 수행에 필요한 명령어 경로를 Parsing 하는 것을 의미함.

학부 때 배웠던, 신입 때 배웠던 기본을 지키지 못해서 프로젝트가 초 딜레이되었다.

잊지 않기 위해서 정리하자.

작은 범위에서 큰 범위까지 모두 아래의 흐름이 잘 이뤄져야 한다.

 

1. 문제 정의

[망한 이유]

(1) 문제를 제대로 정의했다고 생각했는데, 문제를 정의한 게 아닌 해야할 거를 정의함

[결론]

* 어떤 상황, 어떤 부분 디테일하게 문제가 무엇인지 정확히 알자.

 

2. 요구 사항 개발

[망한 이유]

(1) 초기 요구 사항을 꼼꼼히 수립하지 못함 (확장성 여부 생각 안 함 및 일정에 쫒겨 시간 할애하지 않음)

(2) 프로젝트 중간에 요구 사항이 바뀜 (당연하게 4년 짬밥으로 예측했어야 했는데 안 함)

(3) 프로젝트가 끝나고 새로운 요구 사항이 생김 (초기 회의에서는 해당 요구사항에 대한 불필요함을 말하며 사라졌는데, 갑자기 해야할 것으로 바껴있음... 의사소통 문제인 지, 무슨 문제인 지 참 회사 생활 어려움)

[결과]

* 어디서부터 손을 대야 할 지 막막해짐. (바뀐 요구사항과 새로운 요구사항에 대한 추가 개발이 기존 요구사항에서 개발한 부분과 충돌, 유연성 고려하지 않은 대가)

 

3. 구현 계획 수립

[망한 이유]

(1) 기존 시스템 파악이 덜 되어 가능성 여부가 불투명함 (시스템이 너무 큼, 아직도 일부만 파악함, 조금 슬럼프...)

(2) 가능성 여부를 모르는 일정 산정이 너무 어려움 (일정 산정은 참... 어떻게 보면 예습과 같다... 짬내서 해야하는 것)

[결과]

* 결국 동작하지 않음 (구현을 성공적으로 수행하기 위한 기초 작업의 검증이 필요함 - Prototype 구현)

* 기초 작업의 가능성을 보긴 했는데, 현재 구축된 시스템 안에서 적용하는 게 배꼽이 배보다 더 커지는 상태

 

4. 소프트웨어 아키텍처 또는 상위 수준 디자인

[망한 이유]

(1) 초반에는 그래도 설계 흉내를 내었는데, 말 그대로 흉내였음

(2) 기존 설계를 파악하지 않고 내 멋대로 설계를 진행함

(3) 이론 상 설계와 실제 설계의 차이점이 너무 큼 (선배에게 자문을 구했는데, 너무 선배의 지식에만 의존)

[결과]

* 예측과 계속 다른 결과가 나타나며, 처음 예측했던 것보다 더욱 더 거대해져버림

 

5. 상세 설계

[망한 이유]

[결과]

* 상세 설계 단계를 하지 않음. 초기 설계대로 붙잡고만 있다가 꾸역 꾸역 진행

 

6. 코드 작성 및 디버깅

[망한 이유]

(1) 초기 설계 단계에서 머물러 변화하는 요구사항에 대한 상세설계를 하지 않았으니 명확한 코드 작성이 안 됨

(2) 꼬일대로 꼬여서 여기 수정하면 저기가 터지고, 저기 수정하면 또 다른데가 터져버림

[결과]

* 무한 디버깅 시작...

 

7. 단위 테스트

[망한 이유]

(1) 테스트 케이스 없음

(2) ASSETE() 문 고려하기엔 동작 돌아가는 데에 급급 (내가 아닌 코드 리뷰에 맡김)

[결과]

* 테스트 점검 결과 얼마나 많은 이슈가 나올 지 무서움

 

8. 통합 테스트

[망한 이유]

[결과]

* 하지 않음

 

9. 통합

[망한 이유]

(1) 막연히 이럴 거라고 예측하고 구현한 부분들을 넣었는데, 알고보니 생각보다 훨씬 더 거대했음

(2) Task Branch를 Merge하는 과정 중에 Code-Conflict 무수히 발생

(3) 꾸준히 Branch 병합하면서 진행했으면 Risk 관리가 되었겠지만, 나중에 끝내고 한 방에 해야지 했다가 한 방에 KO

[결과]

* Side-Effect의 시작

 

10. 시스템 테스트

[망한 이유]

[결과]

* 하지 않음

 

11. 유지 보수

[망한 이유]

(1) 구조를 알고 설계하기보다, 설계 없이 기존 구조에 넣으면서 작업하였으므로 Side 예측이 되지 않음

[결과]

* 꼼꼼히 테스트했다고 생각했는데, 하나를 고치면 다른 곳에서 또 하나 문제가 터지고, 계속된 옆그레이드의 반복

 

12. 결론

앞으로는 반드시 소프트웨어 개발 절차에 맡게 프로젝트를 진행해서 성공적으로 마무리를 짓자.

벌써 취업한지 3년이 됐구나.

세월 빠르다.

곧 결혼도 할 것 같다.

무섭다.

 

카페에서 무서워하던 와중에 취업당시 판교에서 n자형 건물에서 기술 면접 볼 때가 생각났다.

이 때 기술면접 진행 방식은 다음과 같았다.

여러 게임 개발 팀에서 면접보고 싶은 지원자를 선택했다.

그래서 스펙이 좋으신 분들은 여러번의 기술 면접을 볼 수 있었고

나같은 경우에는 오직 1팀만이 면접보고싶어했다.

그 때는 그것만으로 기적같았다.

요즘도 핫한 그 팀.

내가 게임에 빠지게 만들었던 그 게임의 팀.

니니지.

 

초등학교 6학년 때 사촌형으로부터 이 게임의 존재를 처음 알게되고

숱하게 3일 무료 계정을 이용해서 요정의 숲 노가다와 용의계곡 먹자를 하던 추억이 담긴 게임.

내게 사기란 사기는 다 경험하게 만들어 인간의 악독함을 알게해 준 게임.

초6때 '신선조천검'이란 아이디를 체렙까지 찍기위해 어머니에게 내기를 했다.

만약 반에서 1등하면 월정액 2만9천700원을 결제해딸라!

그리고 거짓말같이 중간고사? (초등학생도 있었나? 가물가물하다.)

에서 반에서 1등해버렸다.

이 때문에 어머니는 내가 천재인줄 알고 각종 학원에 등록하러 다니셨다.

나에게 그런 게임이다.

니니지는.

 

잡소리가 길었는데

아무튼 기술면접에 오게되니 신기했다.

만약 입사하게 된다면 연봉으로 반드시 집행검을 구하리라 생각하고

n자형 건물에 들어갔다.

 

진심 건물 너무 좋다.

두근두근했다.

대기시간동안 하필 환절기 시즌이라 환절기 알레르기와 긴장이 겹쳐서 콧물이 막 났는데

응급처방을 위해 화장실에서 열나게 팔굽혀펴기를 하다가 화장실에 들어오던 한 직원분과 마주친 기억은 넘 쪽팔리다.

아무튼 이런 우여곡절 끝에 드디어 기술면접 장소로 들어갔다.

 

진행을 다음과 같았다.

자기소개가 끝나자마자 손코딩을 시키셨다.

1부터 100까지 더하는 함수를 3가지 방식으로 작성하시오.

for문

while문

재귀적 방식

...

문제만 듣고 너무 쉬워서 코웃음치다가 콧물이 나올뻔했다.

조심하자.

 

그런데 손코딩은 항상 이상한 마력이있다.

마치 무대공포증에 걸린 사람이 무대에 세우게 만드는 그런 이상함.

 

for문과 while문을 지나 재귀적방식 손코딩을 하는데

재귀 어떻게 하는거였지?

막막하다.

주어진 시간은 5분이었는데 한 4분동안 ... 진심으로 뻘짓했다.

슬쩍 심사위원 분들 표정을 봤는데

코웃음치더니 그것도 못푸냐?

이런 표정.

그러다 행운의 신이 강림했다.

갑자기 재귀 방식에 대한 그간 공부했던 부분들이 머릿속에 파바밧 꽂히더니

순식간에 적어냈다.

다행이다.

심사위원분들의 표정도 덩달아 좋아지셨다.

 

이게 은근 웃긴게 나중에 면접을 마치고 대기실에 가보니

나보다 월등한 스펙을 가지셔서 3번의 기술 면접을 앞 두신 분도 이 문제를 풀지못해 속상해하셨다.

너무 쉬운 건데 긴장하셔서 머릿속에 아무 생각이 안들어 못푸셨다고 한다.

 

이해된다.

나도 그럴뻔했다.

 

다행히 손코딩을 풀고나니 이번에는 A4용지 한장을 주셨다.

영어로 작성된 한 API의 함수였는데

이를 읽고 어떤 기능의 함수인지 설명해보라하셨다.

 

다행히 나는 영어에 조금 자신이 있었다.

손코딩도 해결했다는 자신감 덕택에 무리없이 그 함수에 대해 설명했다.

물론 함정카드도 존재했다.

아주 교묘하게 처음은 읽기 쉽지만 중간에 똑바로 해석안하면 기능 자체가 달라지는 함수였다.

기억은 잘 안난다.

스트링관련된 함수였는데.

아마 영어 읽기 능력과 꼼꼼함을 보는 면접같았다.

 

위의 2번의 실기를 거치고 이제 본격적인 면접이 시작됐다.

여러 질문들.

그 중에서 이제 기억나는 것은 realloc()에 대한 위험성에 대한 질문과

대망의 이번 포스트를 위한 질문.

바로 메모리 처리에 대한 질문이다.

 

이 질문의 도입은 이러했다.

혹시 가비지콜렉션(Garbage Collection)의 원리에 대해서 아느냐.

 

당연히 몰랐다.

그래도 주워들은것은 있어서 고민했다.

아는척 말해볼까. 아니면 솔직하게 잘 모르고 주워들은 것만이라도 이야기해볼까.

 

당연히 나는 후자다.

아는척하면 끝맛이 좋지않았다. 항상.

 

가비지콜렉션의 참조와 사용 빈도에 따른 그리고 세대별로 나뉘어진 메모리 관리 부분에 대해서 설명했더니

다시 나에게 물어보셨다.

가비지콜렉션이 장단점에 대해서.

 

이건 그래도 말하기 편했다.

속도와 안정성의 반비례적인 문제.

JAVA와 C#은 가비지콜렉션을 통해서 메모리 할당과 해제에 대해서 신경쓸 필요가 없다.

(사실 경험해보니 조금 필요하다. 특히 해제 시점이 명확하지 않아서 더 어려웠다.)

대신 이를 위해서 두 언어 모두 가상머신이라는 개념이 존재하므로 당연히 속도는 느리다.

이렇게 설명했던 것 같다.

 

여기까지 왔을 때 나는 이번 면접에 대해서 합격할 자신이 생겼다.

슬슬 면접 시간도 다되가는것 같고 분위기가 굉장히 모닥불 앞에 있는 것처럼 훈훈했다.

 

그러던 와중에 들은 질문.

그럼 C++에는 이렇게 알아서 메모리 관리를 해주는 가비지콜렉션이 없는데

안전하게 메모리를 해제하려면 어떻게 해야할까요?

 

지금보면 이 기술면접 질문중에서 가장 쉽다.

왜냐하면 이미 스마트포인터의 존재를 알기 때문이다.

 

그런데 이 때에는 나는 스마트포인터의 존재를 몰랐다.

잘 나가던 면접이 틀어졌다.

한 호흡에 메모리 할당과 해제를 해야한다.

독립성을 잃으면 안된다.

한참을 헛소리했다.

 

지금 생각하면 이 질문은 스마트포인터의 존재를 아냐고 물어본 질문이었다.

그런데 모르니까 당연히 헛소리를 할 수 밖에 없다.

그렇게 내 기술면접 마지막 질문이 끝났다.

관심있으면 한 번 이 부분에 대해서 찾아보세요. 라는 말과 함께.

 

이 말은 날 굉장히 심숭생숭하게 만들었다.

합격인가? 불합격인가? 아니면 그냥 조언?

떨렸다.

스마트포인터는 C++ 개발자라면 반드시 알아야한다.

스택 오버플로우에서는 RAII라는 개념을 통해 이미 이 C++ 메모리 관리에 대한 논의는 얼추 정리된 상태다.

다음에는 이 부분에 대해서 스택 오버플로우 번역 포스트를 올려야겠다.

 

그래서 결과는...

 

두구두구두구

 

합격!

 

눈물이 터졌다.

그리고 간 최종 면접.

그 때에 나는 깝치지 말았어야 했다.

신입 지원자였어야 했는데 게임 유저가 되버렸다.

 

그 때 최종면접에서 마지막으로 하고싶은 말이 있냐고 물었을 때

당시의 게임 현질 문화에 대해서 너무 과도하다

라고 말하지않았다면 결과가 달라졌을까?

 

물론 변명이다.

그냥 실력부족.

 

지금 니니지m을 보면 회사 입장에서는 분명 당시 정책의 성공이라고 말할 수 있겠다.

다른 게임 업체들이 휘청거릴 때 사상 최고의 주가를 경신중이다.

회사 입장에서는 어마어마한 성공이겠지만

게임 유저로서는 솔직히 이 문화가 아쉽다.

 

그래도 잘 나가고있으니 좋다.

내가 그렇게 힘들었던 시절에 내게 희망과 기회를 줬던 곳이었으니까.

끝.

 

+ Recent posts