├── C++ ├── L-value, R-value.md ├── Move Semantics - 이동 의미론.md ├── Name Mangling (Decoration).md ├── Sort 복잡도 정리.md ├── algorithm sort는 어떤 알고리즘인가.md ├── cast.md ├── const.md ├── mallocfree vs newdelete.md ├── map vs unordered_map.md ├── static.md ├── struct, class.md ├── template.md ├── typedef vs using(별칭 선언).md ├── vector와 관련한 이야기들.md ├── 가상 소멸자.md ├── 가상함수.md ├── 상등성과 동등성.md ├── 스마트 포인터.md ├── 얕은복사와 깊은복사.md ├── 오버로딩 오버라이딩.md └── 포인터와 배열의 차이.md ├── DB ├── Key.md └── 정규형.md ├── DesignPattern ├── AdapterPattern.md ├── FacadePattern.md ├── NullObjectPattern.md ├── ObserverPattern.md ├── ProxyPattern.md ├── SingletonPattern.md ├── StatePattern.md └── StrategyPattern.md ├── License ├── OOP └── 객체지향5원칙.md ├── OS ├── CPU 스케쥴러의 알고리즘 종류.md ├── DeadLock (데드락, 교착 상태, 이하 데드락).md ├── 가상 메모리 - Virtual Memory.md ├── 리틀 앤디언, 빅 앤디언.md ├── 메모리 단편화 - Memory Fragmentation.md ├── 뮤텍스(Mutex)와 세마포어(Semaphore).md └── 프로세스와 스레드.md ├── Personality Interview └── 게임 클라이언트 인성,경험 질문.MD ├── README.md ├── Unity_C# ├── Awake_Start_Update_FixedUpdate_LateUpdate.md ├── C# vs C++.md ├── C#의 string.md ├── List_Dictionary.md ├── Unity & C#의 GC.md ├── Unity의 생명주기.md ├── const readonly.md ├── delegate와 event.md ├── this.md ├── 박싱, 언박싱.md └── 직렬화 - Serialization 역직렬화 - Deserialization.md └── Unreal ├── IsValid.md └── Unreal String Classes.md /C++/L-value, R-value.md: -------------------------------------------------------------------------------- 1 | # L-value, R-value 2 | 3 | 간단한게 요약하면 4 | 5 | - L-value는 메모리 위치를 참조하는 식 6 | - R-value는 해당 표현식이 끝나면 더이상 참조할 수 없는 값 7 | 8 | 입니다. 여기서 모든 L-value는 R-value가 될 수 있지만 R-value는 L-value가 아닐 수도 있습니다. 9 | 10 | 11 | 12 | ## 이 둘의 어원 13 | 14 | 과거에는 연산자 = 를 기준으로 왼쪽에 있으면 L-value, 오른쪽에 있으면 R-value 라고 했습니다. 다만 이 말은 **정답이 아니며** 대충 이정도의 느낌의 어원이라 생각하면 됩니다. 15 | 16 | 17 | 18 | ## C++의 R-value reference 19 | 20 | 보통의 경우 `&`를 통한 참조(L-value reference)를 알게 되는데 C++11이후로는 `&&`을 통해 R-value Reference를 만들 수 있습니다. 21 | 22 | 이 `&&`를 통해서 C++의 move semantics, 스마트 포인터 등의 질문이 자연스레 갈 수 있습니다. -------------------------------------------------------------------------------- /C++/Move Semantics - 이동 의미론.md: -------------------------------------------------------------------------------- 1 | # Move Semantics - 이동 의미론 2 | 3 | 4 | C++ 11부터 들어오게 된 중요 개념으로 기술면접 시작으로 나오기도 하는 질문입니다. 이전 C++ 에서는 복사만을 사용했기에 생성이나 대입에 있어서 연산이 느렸습니다. 하지만 C++ 11 후로부터 `&&`연산자를 통한 r-value 참조가 되게 됩니다. 이를 이용해서 기존 객체가 실제로 이동하는게 아닌 객체를 가리키는 포인터의 이동이 있는 것입니다. 타 언어에서의 얕은 복사라고 생각하면 됩니다. 5 | 6 | 이를 사용하기 위해서는 각 객체, 클래스에 이동 생성자, 이동 대입 연산자가 정의되어 있어야 사용이 가능합니다. 7 | 8 | 앞서 말한 '객체 이동이 아닌 포인터의 이동'이라는 점 때문에 이전에 소유하고 있는 객체가 포인터를 들고 있으면 한쪽에서 delete를 할 때 dangling pointer문제가 생길 수 있습니다. 때문에 이전에 소유하던 객체는 nullptr을 가지게 만드는 편입니다. 9 | 10 | 11 | 12 | [이와 관련한 Stackoverflow의 좋은 글](https://stackoverflow.com/questions/3106110/what-is-move-semantics) 13 | 14 | 15 | 16 | ## std::move의 역할 17 | 18 | std::move는 실제 이동을 해주는 함수가 아닌 l-value를 r-value로 바꿔주는 역할을 합니다. 이를 통해서 이동 연산자가 정의되어 있는 경우 변경된 r-value로 오버로딩이 될 수 있는 것입니다. 19 | 20 | 대략 아래 코드의 느낌이라고 보시면 됩니다. 21 | 22 | ```c++ 23 | template 24 | typename remove_reference::type&& move(T&& param) 25 | { 26 | using ReturnType = typename remove_reference::type&&; 27 | 28 | return static_cast(param); 29 | } 30 | 31 | // C++ 14 이후 32 | template 33 | decltype(auto) move(T&& param) 34 | { 35 | using ReturnType = remove_reference_t&&; 36 | 37 | return static_cast(param); 38 | } 39 | ``` 40 | 예시코드입니다. 41 | ```cpp 42 | std::vector v; 43 | std::string str = "example"; 44 | v.push_back(std::move(str)); // str 은 이제 껍데기만 남음 45 | str.back(); // 정의되지 않은 작업! 46 | str.clear(); // 다만 clear 자체는 가능하다. 47 | ``` 48 | 49 | 때문에 실제로 하는 일은 move 가 아닌 rvalue_cast 입니다. 50 | 51 | 52 | 53 | ## std::forward의 역할 54 | 55 | std::forward의 경우에는 move와 다르게 오른값일때는 오른값으로 전달, 왼값일 때는 왼값으로 전달하는 역할을 합니다. 56 | 57 | 58 | 59 | > std::forward는 어떻게 왼값, 오른값을 알 수 있는가? 60 | 61 | ```C++ 62 | template 63 | T&& forward(typename remove_reference::type& param) 64 | { 65 | return static_cast(param); 66 | } 67 | ``` 68 | 69 | std::forward는 C++의 템플릿 매개변수 연역 방식을 통해 알아내게 됩니다. 여기서 C++은 원래 참조에 대한 참조는 안되지만 **특정 문법에서는 참조에 대한 참조가 허용됩니다. 그게 템플릿 인스턴스화 입니다.** 그리고 추가적으로 C++ 에서는 **연역 과정에서 둘 중 하나라도 l-value 참조라면 결과는 l-value 참조**가 된다는 규칙이 있어 std::forward는 이런 전달을 할 수 있는 것입니다. 70 | 71 | 72 | 73 | 아래 코드를 보면 어느정도 이해할 수 있게 됩니다. 74 | 75 | - Some& 가 전달된 경우 76 | 77 | ```C++ 78 | Some& && forward(typename remove_reference::type& param) 79 | { 80 | return static_cast(param); 81 | } 82 | ``` 83 | 84 | - Some&& 의 경우에는 T가 Some로 연역됨 85 | 86 | 87 | 88 | ## move 대신 다 forward 쓰면 되는거 아닌가? 89 | 90 | move와 forward의 차이는 forward는 조건에 따른 캐스팅을 한다는 이야기입니다. 때문에 다 move의 존재 의의를 묻게 됩니다. 91 | 92 | 일단 move의 경우는 사용이 편하고 코드의 명확성이 좋아집니다. 둘의 역할도 약간의 차이가 있는것이 move의 경우는 이동 준비가 목적이고 forward의 경우는 전달이 목적입니다. 때문에 이런 구별되는 이름을 두는게 바람직합니다. 93 | -------------------------------------------------------------------------------- /C++/Name Mangling (Decoration).md: -------------------------------------------------------------------------------- 1 | # Name Mangling (Decoration) 2 | 3 | >Mangle : ~을 난도질하다 (파파고) 4 | 5 | 6 | 7 | `Name Mangling`은 컴파일러가 함수나 변수의 이름을 임의로 변경하는 작업입니다. 이런 작업이 C++에서 일어나는 이유는 `함수 오버로딩`때문인데 만일 같은 이름의 함수들이 있고 시그니처들이 다르다고 할 때 컴파일러는 이들의 이름을 다르게 부릅니다. 8 | 9 | - 만일 SomeFunc(), SomeFunc(int some) 가 있다고 하면 10 | 11 | - SomeFunc()는 컴파일러가 SomeFunc_ 로 12 | - SomeFunc(int some)는 컴파일러가 SomeFunc_i 로 13 | 14 | 같은 이름으로 변경하게 됩니다. 15 | 16 | 17 | 18 | > 이런 네이밍 규칙에 대해서 물어보지는 않겠지만 궁금하신 분들을 위한 [Wiki](https://en.wikipedia.org/wiki/Name_mangling) 링크입니다. 19 | 20 | 21 | 22 | ## C에서도 이런 Name Mangling는 있는가? 23 | 24 | 일단 C 에서는 함수 오버로딩이 없기에 이런 Name Mangling이 필요 없습니다. 다만 컴파일러에 따라 다르기는 한데 앞에 `_`를 붙이는 등의 작업을 하기는 합니다. 25 | 26 | 한다 안한다에 대한 이야기는 여러 의견이 갈리는 모습이 있습니다. 어떤 곳에서는 하지 않지만 대부분의 경우 **C는 간단한 Name Mangling을 한다**라는 의견이 주류인 것 같습니다. 27 | 28 | > 현재 이 C에 대한 내용을 제보받고 있습니다. 29 | > 30 | > 컴파일을 한 뒤 확인을 하면 Mangling이 된 모습을 볼 수 있는데 이걸 확실하게 받침해줄 공신력 있는 자료가 필요한 상황입니다. 31 | 32 | 33 | 34 | ## extern "C" 35 | 36 | 해당 명령어는 컴파일 후 이후 내용을 C 처럼 만들어 주기에 C++에서 작성을 한다 해도 C 에서 사용할 수 있게 해주는 명령어 입니다. 37 | 38 | ```C++ 39 | extern "C" int Some(int a) 40 | { 41 | //... 42 | } 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /C++/Sort 복잡도 정리.md: -------------------------------------------------------------------------------- 1 | 2 | #### Sorting Algorithm's Complexity 정리 3 | 4 | | Algorithm | Space Complexity | (average) Time Complexity | (worst) Time Complexity | 5 | | :------------: | :--------------: | :-----------------------: | :---------------------: | 6 | | Bubble sort | O(1) | O(n^2) | O(n^2) | 7 | | Selection sort | O(1) | O(n^2) | O(n^2) | 8 | | Insertion sort | O(1) | O(n^2) | O(n^2) | 9 | | Merge sort | O(n) | O(nlogn) | O(nlogn) | 10 | | Heap sort | O(1) | O(nlogn) | O(nlogn) | 11 | | Quick sort | O(1) | O(nlogn) | O(n^2) | 12 | | Count sort | O(n) | O(n) | O(n) | 13 | | Radix sort | O(n) | O(n) | O(n) | 14 | -------------------------------------------------------------------------------- /C++/algorithm sort는 어떤 알고리즘인가.md: -------------------------------------------------------------------------------- 1 | # sort는 어떤 알고리즘인가 2 | 3 | 간단하게 요약하면 헤더에 있는 sort 함수는 `인트로 소트(introsort)`를 사용하고 있습니다. 4 | 5 | 이전에는 퀵 정렬를 사용했다고 하나 퀵 정렬의 고질적인 문제인 최악의 시간복잡도에서는 O(N^2) 시간복잡도가 나온다는 점에서 이 인트로 소트를 채용을 한 것입니다. 6 | 7 | 인트로 소트는 총 3개의 알고리즘이 섞이게 됩니다. 8 | 9 | - 퀵 정렬 10 | - 힙 정렬 11 | - 삽입 정렬 12 | 13 | 내부의 구현사항을 사용자가 알 수 없게 잘 캡슐화 한 사례이며 배열의 크기가 작다면 삽입 정렬, 크기가 크면 퀵 정렬을 사용하다가 오래 걸린다 판단이 되면 힙 정렬을 사용하는 것으로 구현되어 있습니다. 14 | 15 | 16 | 17 | ## 인트로 소트의 자세한 부분 18 | 19 | - 배열을 나눈 각 파티션 크기가 최대 깊이 제한인 2LogN을 넘을 가능성이 있다면 힙소트가 됩니다. 20 | 21 | - 파티션의 원소가 16개 이하로 작아지면 삽입 정렬이 됩니다. 22 | - 파티션 크기가 제한 미만이고 너무 작지 않다, 즉 16 ~ 2LogN 크기라면 퀵 정렬을 합니다. 23 | 24 | 삽입 정렬을 넣은 이유는 **삽입 정렬이 작은 배열에 대해서, 정리가 거의 다 된 배열에 대해서 빠른 속도를 가지기 때문**입니다. 25 | 26 | 27 | 28 | 여기서 머지 소트를 사용하지 않은 이뉴는 N 만큼의 공간이 추가적으로 필요하기에 사용하지 않습니다. 29 | 30 | 31 | 32 | ## 그러면 List의 경우에는? 33 | 34 | List와 같은 자료구조는 알고리즘 헤더의 sort 함수로 동작하지 않습니다. 이는 리스트가 랜덤 접근이 안되기 때문이며 List는 자료구조의 멤버 함수 sort를 사용해야 합니다. 35 | 36 | 그리고 리스트의 내부 정렬 함수는 일반적으로 머지 소트를 사용하게 됩니다. 때문에 시간 복잡도는 O(NlogN)이 됩니다. 37 | 38 | -------------------------------------------------------------------------------- /C++/cast.md: -------------------------------------------------------------------------------- 1 | # C++ cast 2 | 3 | 캐스팅은 일단 명시적 캐스팅, 묵시적 캐스팅으로 나뉘게 됩니다. 4 | 5 | 묵시적 캐스팅의 경우에는 다른 표기 없이 호환되는 타입들로 변환할 수 있게 해주지만 데이터 손실이 발생할 수도 있고 유지보수 측면에서도 알아내기 어려우므로 가급적 사용하지 않는게 좋습니다. 6 | 7 | 8 | 9 | C 스타일의 명시적 캐스팅은 아래와 같습니다. 10 | 11 | ```c++ 12 | float f = 1.1f; 13 | int a = (int)f; 14 | ``` 15 | 16 | 다만 이 경우 코드 분간이 어렵기도 하고 C의 유산이므로 C++의 여러 캐스팅 연산자들을 사용하게 됩니다. 17 | 18 | 19 | 20 | ## static_cast 21 | 22 | 기존 C스타일의 형변환 대신 사용하게 됩니다. 형변환이 가능한지에 대한 검사는 컴파일 타임에 하게 됩니다. 23 | 24 | ```c++ 25 | float f = 1.1f; 26 | int a = static_cast(f); 27 | ``` 28 | 29 | 30 | 31 | ## const_cast 32 | 33 | 이는 const를 제거, 부여하는데 사용이 됩니다. 다만 부여의 경우에는 사용하는 경우가 잘 없게 됩니다. 34 | 35 | ```c++ 36 | void NonConstFunc(Some s); 37 | 38 | //... 39 | const Some s; 40 | NonConstFunc(s); // ERROR! 41 | NonConstFunc(const_cast(s)) 42 | ``` 43 | 44 | 45 | 46 | ## reinterpret_cast 47 | 48 | 모든 포인터 유형을 다른 포인터 방식으로 변경할 수 있게 됩니다. 또한 포인터 타입을 정수로 바꾸는데도 가능한 캐스팅입니다. 49 | 50 | 이런 식으로 강력한 형변환을 하기 때문에 자주 사용하지 않게 되며 메모리 단위로 분해, 재조립을 하는 캐스팅이므로 이해도가 필요한 캐스팅입니다. 51 | 52 | 53 | 54 | ## dynamic_cast 55 | 56 | 클래스의 포인터나 참조에만 사용할 수 있으며 런타임에 캐스팅을 진행하게 됩니다. RTTI(Runtime Type Information)를 위한 캐스팅이라 할 수 있습니다. 다만 클래스간 virtual 함수가 있어야 하며 만일 다형성이 없는 객체들 간 캐스팅에서는 컴파일 에러가 나오게 됩니다, -------------------------------------------------------------------------------- /C++/const.md: -------------------------------------------------------------------------------- 1 | # const 2 | 3 | const 는 해당 값이 상수임을 지정하고 프로그래머가 초기화 외 이를 수정할 수 없게 하는 키워드입니다. 4 | 5 | 6 | 7 | ## const와 포인터 8 | 9 | 포인터`*`의 위치에 따라 const는 의미를 다르게 가지게 됩니다. 10 | 11 | ```C++ 12 | const int* var = &someNumber; 13 | 14 | someNumber = 2; // OK 15 | *var = 2; // ERROR!ERROR!ERROR! 16 | ``` 17 | 18 | `*`의 왼쪽에 오는 const의 경우에는 **가리키는 값에 대해 상수화**를 한다는 의미입니다. 19 | 20 | 21 | 22 | ```C++ 23 | int* const var = &someNumber; 24 | 25 | var = 2; // OK 26 | var = &anotherNumber; // ERROR!ERROR!ERROR! 27 | ``` 28 | 29 | `*`의 오른쪽에 오는 경우에는 **포인터 변수가 상수화 되어 가리키는 주소를 고정** 한다는 이야기입니다. 30 | 31 | 32 | 33 | ## 클래스에서 const 34 | 35 | 멤버 변수의 const 는 위의 의미를 따라 한번 결정되면 변경되지 않는 값을 의미합니다. 클래스에서 선언하면 **반드시** 초기화를 해줘야 하며 C++11부터는 클래스 내부에서 `const auto var = 1` 과 같은 형태의 선언이 가능하지만 대부분의 경우 생성자의 초기화 리스트에서 초기화를 해 줍니다. 36 | 37 | 멤버 함수의 const는 반환값이 const 이냐, 함수가 const이냐에 따라 달라집니다. 38 | 39 | - 반환값이 const라면 당연하게도 **반환값이 상수**라는 이야기입니다. 40 | - 함수가 const 인 경우에는 해당 함수 내에서 멤버 변수들을 **읽기 전용**으로 보겠다는 이야기입니다. 41 | - 멤버 변수에 대한 수정(할당)등을 할 수 없습니다. 42 | - 다른 멤버 함수를 부를 때는 const 인 함수만 호출가능합니다. -------------------------------------------------------------------------------- /C++/mallocfree vs newdelete.md: -------------------------------------------------------------------------------- 1 | # malloc/free vs new/delete 2 | 3 | malloc/free는 함수, new/delete는 연산자인게 가장 큰 차이점입니다. 4 | 5 | - malloc/free 6 | - #include "stdlib.h" 를 해줘야 사용 가능 7 | - malloc는 void 함수이기 때문에 반환받은걸 해당 타입의 포인터로 형변환을 해줘야 합니다 8 | - 생성자를 호출할 수단이 없기에 초기값을 줄 수 없다는 단점이 있습니다. 9 | - 역시 free의 경우에도 소멸자를 부르는게 아닌 함수 호출입니다. 10 | - malloc로 할당한 경우에는 `realloc`을 활용해 메모리 크기를 조정할 수 있습니다. 11 | - new/delete 12 | - new/delete는 기본적으로 C++ 내 있는 키워드로 따로 include 할게 없습니다. 13 | - new를 했을 시에는 반환값이 해당 타입의 포인터로 자동 반환이 됩니다. 14 | - 생성자를 호출해 초기값을 줄 수 있습니다. 15 | - delete는 소멸자를 호출해 줍니다. 16 | - new 로 할당한 경우 직접적으로 메모리 크기를 조정할 수 없습니다. 17 | - 때문에 재할당이 많다면 malloc가 나은 방법이 될 수도 있습니다. 18 | 19 | -------------------------------------------------------------------------------- /C++/map vs unordered_map.md: -------------------------------------------------------------------------------- 1 | # map vs unordered_map 2 | 3 | 둘 다 key, value 쌍으로 되어 있지만 내부 자료구조가 다르게 동작하게 됩니다. 4 | 5 | - map의 경우 [레드 블랙 트리](https://ko.wikipedia.org/wiki/%EB%A0%88%EB%93%9C-%EB%B8%94%EB%9E%99_%ED%8A%B8%EB%A6%AC)로 되어 있는 자료구조로 내부 원소들이 key에 따라 정렬됨 6 | - unordered_map의 경우에는 해시 테이블이 기반으로 되어 정렬이 없음 7 | 8 | 자료구조의 차이로 인해서 map은 일반적으로 O(logN) 시간 복잡도를 가지게 되고 unordered_map의 경우에는 주로 O(1) 시간 복잡도를 가지게 됩니다. 다만 최악의 경우에는 O(N) 시간 복잡도를 가질 수 있습니다. 9 | 10 | 11 | 12 | > 추가적으로 해시 함수는 역함수가 없습니다 13 | 14 | 15 | 16 | ## unordered_map과 체이닝(chaining) 17 | 18 | 해시함수를 통과한 뒤 값이 같은 경우가 있습니다. 이런 경우에는 리스트처럼 체이닝을 통해 관리를 하게 됩니다. 이로 인해서 최악의 시간 복잡도가 O(N)이 나올 수 있게 되는 것입니다. 19 | 20 | 21 | 22 | > 또 추가적인 개선 방법으로는 [Open Addressing](https://en.wikipedia.org/wiki/Open_addressing) 이 있습니다. 23 | 24 | 이는 충돌 발생시 다른 자리에 저장하는 방법으로 Linear Probing, Quadratic Probing, Double Hashing 이 있습니다. 25 | 26 | - Linear Probing은 해당 해시 값에 자리가 있다면 근처 빈 슬롯에 저장하는 것입니다. 27 | - hash(n), hash(n) + 1, hash(n) + 2 순서로 검색하며 만약 테이블의 끝에 간다면 다시 테이블 처음으로 돌아와서 검색합니다. 28 | - Quardratic Probing 29 | - +1^2, +2^2, +3^2 의 방식으로 올라가게 됩니다. 30 | 31 | - Double Hashing 32 | - 서로 다른 두 해시 함수를 사용하게 됩니다. 33 | 34 | 35 | 36 | ## 여기서 좋은 해시 함수는 무엇일까? 37 | 38 | 좋은 해시 함수는 [SUHA - Simple Uniform Hashing Assumption](https://en.wikipedia.org/wiki/SUHA_(computer_science)) 이라 해서 각 해시 Key가 균등하게 분배되는 것을 의미합니다. 이를 통해 해싱 충돌을 최대한 막는게 좋은 함수라는 뜻입니다. 39 | 40 | 다만 이는 이론적인 이야기로 해시 함수의 성능 분석때 사용하게 됩니다. -------------------------------------------------------------------------------- /C++/static.md: -------------------------------------------------------------------------------- 1 | # static 멤버 변수 2 | 3 | 클래스의 static 멤버 변수는 **모든 클래스의 인스턴스들이 공유하는 멤버**로 프로그램의 수명 내 한번만 초기화되면서 계속해서 메모리에 올라가 있게 됩니다. 4 | 5 | ```c++ 6 | class Some 7 | { 8 | private: 9 | static int var; 10 | 11 | // Some() 12 | // : var(1) 13 | // {} -> 생성자 내에서도 초기화 불가능 14 | 15 | } 16 | 17 | int Some::var = 0; // 전역 범위에서 초기화 가능합니다. 18 | ``` 19 | 20 | 만일 헤더와 cpp 파일을 분리해서 개발하는 경우 반드시 cpp파일에서 초기화를 해줘야 합니다. 21 | 22 | 추가로 이 멤버의 접근 지정자가 private이라 하더라도 전역범위 초기화가 가능합니다. 23 | 24 | 25 | 26 | 다만 **static const 변수의 경우에는 클래스에서 초기화 하는 것이 가능**합니다. 이는 [const]()의 특성 상 값을 변경하는게 불가능하며 컴파일 타임 초기화가 되므로 가능합니다. 27 | 28 | 29 | 30 | # static 멤버 함수 31 | 32 | 클래스 내 static 함수는 모든 클래스가 공유하는 함수로 객체와는 관계 없이 호출될 수 있습니다. 33 | 34 | 이 함수 내에서는 일반 멤버 변수, 즉 `this`가 붙는 멤버에 대해서는 연산을 할 수 없습니다. 다만 static 멤버 변수, 함수에 대한 연산을 사용할 수 있습니다. -------------------------------------------------------------------------------- /C++/struct, class.md: -------------------------------------------------------------------------------- 1 | # struct, class의 차이 2 | 3 | - 기본 접근지정자가 class는 `private`, struct는 `public` 입니다. 4 | 5 | - 초기화 방식에 대해서도 struct는 아래 초기화 방법이 가능하지만 class는 불가능합니다. 6 | 7 | ```c++ 8 | struct SomeStruct 9 | { 10 | int var; 11 | int varPrivate; 12 | }; 13 | 14 | class SomeClass 15 | { 16 | int var; 17 | int varPrivate; 18 | }; 19 | 20 | int main(){ 21 | SomeStruct someS = {1, 2}; 22 | SomeClass someC = {1, 2}; // ERROR 23 | } 24 | ``` -------------------------------------------------------------------------------- /C++/template.md: -------------------------------------------------------------------------------- 1 | # template 2 | 3 | 4 | 5 | ## 사용 이유 6 | 7 | 중복되는 자료형에 대해서 코드를 중복시키지 않고 일반화를 할 수 있습니다. 그리고 C++에서는 `템플릿 특수화`가 가능해 특정 타입에 대해서는 다른 식으로 동작하게끔 만들 수 있습니다. vector이 템플릿 특수화의 좋은 예시입니다. 8 | 9 | 10 | 11 | ## 템플릿의 장단점 12 | 13 | - 장점 14 | - 컴파일러가 컴파일 타임에 템플릿 인스턴스에 대한 코드를 만들어주기에 런타임에서 속도 이득이 있습니다. 15 | - 또한 타입만 다른, 중복 코드들을 한군데 모을 수 있습니다. 16 | - 컴파일 도중 다형성 부여가 가능하기에 vtable이 없어 더 빠르게 동작합니다. 17 | - 단점 18 | - 컴파일 타임에 인스턴스 생성으로 인해 컴파일 타임이 늘어납니다. 19 | - 이는 템플릿 매개변수로 들어온 종류가 많을수록 늘어납니다. 20 | - 쓸모없는 템플릿 변형을 막을 방법이 없다 21 | - 다형성이 추가될 경우 파일이 커지게 되어 실행 시간이 늘어날 수 있습니다. 22 | -------------------------------------------------------------------------------- /C++/typedef vs using(별칭 선언).md: -------------------------------------------------------------------------------- 1 | # typedef vs using(별칭 선언) 2 | 3 | 4 | 5 | C++11 후로는 using 이라는게 가능하게 됩니다. 6 | 7 | ```c++ 8 | typedef std::unique_ptr> UPtrMapSS; 9 | using UPtrMapSS = std::unique_ptr>; 10 | ``` 11 | 12 | 13 | 14 | 이 둘의 차이를 두고 질문이 오가는데 using 사용을 권장하는 이유 는 포인터 관여시 using이 더 이해하기 쉽다는 점, using은 템플릿화가 가능하다는 점이 있습니다. 15 | 16 | ```c++ 17 | typedef void (*FP)(int, const std::string&); 18 | using FP = void (*)(int, const std::string&); 19 | 20 | template 21 | using AllocWList = std::list>; 22 | 23 | AllocWList some; 24 | 25 | // Code from 'Effective Modern C++' 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /C++/vector와 관련한 이야기들.md: -------------------------------------------------------------------------------- 1 | # vector와 관련한 이야기들 2 | 3 | vector는 C++에서 가장 많이 사용되는 STL이라고 봐도 무방합니다. 때문에 vector의 메모리 관리, list의 차이 등은 알아가는게 좋을 것입니다. 실제로 작성자도 기술면접에서 vector 관련 질문을 받았거든요. 4 | 5 | 6 | 7 | ## vector와 list의 차이 8 | 9 | - vector 10 | - 메모리 내에서 원소들이 연속적인 위치를 가짐 11 | - 랜덤 접근 가능 12 | - 중간 요소를 제거, 추가하는데 O(N) 시간 복잡도를 가지게 됨 13 | - list 14 | - 메모리 내 흩어져 있어 비연속적 위치를 가짐 15 | - 위 특징으로 인해 랜덤 접근이 불가능 16 | - 이중 연결 리스트로 구현이 되어 있음 17 | - 추가, 제거를 어디서 하던 상수 시간 제거가 가능하며 18 | 19 | 20 | 21 | ## vector의 size, capacity (feat. reserve, resize) 22 | 23 | - size : 실제 원소들이 있는 공간 24 | - capacity : 벡터가 차지하고 있는 공간 25 | 26 | reserve는 여기서 capacity를 변경하는 함수이고 resize는 size를 변경하는 함수입니다. 27 | 28 | 29 | 30 | 31 | 32 | ## vector의 기본적인 동작 33 | 34 | vector의 경우에는 연속적인 메모리 공간을 미리 할당을 하게 됩니다. 만일 원소 삽입 시 메모리 공간이 부족하다면 **새 메모리 공간을 할당한 뒤 그곳으로 기존 원소들을 복사**한 다음 새 원소를 삽입하게 됩니다. 35 | 36 | 만일 vector에서 reserve는 많이 되어 있는데 실제 사용하는 공간은 적어 메모리를 아끼고 싶다면. 새 벡터에 복사 후 맞바꾸기 하는 전략이 좋습니다. 37 | 38 | 39 | 40 | ## vector에서 값의 삭제 41 | 42 | vector에서는 erase-remove 구문을 이용해서 제거를 하게 됩니다. 43 | 44 | ```c++ 45 | vector<> v; 46 | //... 47 | v.erase(remove(범위 시작, 범위 끝, 지우고 싶은 원소), v.end()); 48 | v.erase(remove_if(범위 시작, 범위 끝, 지우는 조건), v.end()); 49 | ``` 50 | 51 | 이 둘을 함께 사용하는 이유는 remove는 실제 삭제가 아닌 해당 조건에 부합하는 원소들을 벡터의 뒤에 넣은 뒤 '이 뒤로 밀린 원소들의 시작 범위'를 넘겨주게 됩니다. 52 | 53 | remove 구문들이 실제로 삭제하는게 아닌 위치 변경만을 해주기 때문에 erase와 함께 사용을 하게 되는 것입니다. 54 | 55 | 56 | 57 | ## `vector` 58 | 59 | `vector`의 경우에는 실제 bool을 담는것이 아닌 `프록시 패턴`을 통해서 **마치 bool을 담고 있는 것처럼 동작**하게 됩니다. 60 | 61 | 실제로는 원소 한자리에 8비트의 '비트필드'를 두고 있으며 이건 `vector`이 유일합니다. 62 | 63 | 때문에 실제로 bool이 담긴 자료구조를 사용하고 싶다면 `std::bitset`이나 `deque`을 사용하면 됩니다. 64 | 65 | 66 | 67 | [관련한 필자의 블로그 글](https://husk321.tistory.com/366) 68 | 69 | 70 | 71 | ## vector vs deque 72 | 73 | 위에서 이야기한대로 vector는 연속적인 공간을 가지지만 deque의 경우에는 **각 블록들이 흩어져 있고 이 흩어진 블록들에 대한 컨트롤 블록을 가지게**됩니다. 74 | 75 | 여러 벡터들이 흩어진 형태로 결과적으로 모든 원소들이 연속적인 공간에 있는 것이 아닙니다. 76 | 77 | 78 | 79 | [관련한 필자의 블로그 글](https://husk321.tistory.com/364) -------------------------------------------------------------------------------- /C++/가상 소멸자.md: -------------------------------------------------------------------------------- 1 | # 가상 소멸자와 관련한 이야기 2 | 3 | 상속 관계가 있다면 가상 소멸자를 선언해 주는 것이 좋습니다. 4 | 5 | 만일 소멸자가 비가상으로 되어있고 부모 클래스에서 동적으로 할당한 자료를 소멸자에서 소멸하기로 되어 있다고 합시다. 6 | 7 | 이 상태에서 자식 클래스의 인스턴스가 소멸할 경우 자식 클래스의 소멸자만 불리게 되므로 부모 클래스에서 동적 할당한 자료가 해제되지 않아 메모리 누수의 위험이 있습니다. 8 | 9 | 이를 위해서 상속 관계에서 소멸자는 virtual 선언을 해주는 것이 좋으며 부모 클래스에 virtual 키워드를 붙이면 자식 클래스의 소멸자는 자동으로 virtual이 됩니다. 10 | 11 | 12 | 13 | 추가적으로 소멸자가 불릴 때는 자식 -> 부모 클래스 순으로 불리게 됩니다. -------------------------------------------------------------------------------- /C++/가상함수.md: -------------------------------------------------------------------------------- 1 | # 순수 가상 함수 2 | 3 | - `virtual void foo() = 0;` 4 | 5 | 6 | 함수의 정의가 이뤄지지 않고 함수만 선언한 것이지요. 7 | 이렇게 선언된 순수 가상 함수가 있다면 이를 **추상클래스(abstract class)**라고 부릅니다. 8 | 또한 이 추상클래스는 객체로 만들지 못하고 **상속**으로써만 사용됩니다. 9 | 그리고 추상클래스를 **상속받은 자식 클래스는 무조건 해당 순수 가상 함수를 override 시켜줘야 합니다.** 10 | 11 | 12 | 13 | # 순수 가상함수 vs 일반 가상함수 14 | 순수 가상 함수는 **무조건 재 정의**를 해줘야 하지만 일반 가상함수는 **재 정의를 하지 않아도 되기 때문에** 프로그램상에서 오류로 보지 않습니다. 15 | -------------------------------------------------------------------------------- /C++/상등성과 동등성.md: -------------------------------------------------------------------------------- 1 | # 상등성과 동등성 2 | 3 | 요약하면 상등성은 `operator ==`에 기반을 두게 되고 동등성은 `operator <`에 기반을 두게 됩니다. 4 | 5 | ```c++ 6 | if(!(var1 < var2) && !(var2 < var1)) 7 | { 8 | cout << "이건 동등하다"; 9 | } 10 | ``` 11 | 12 | 표준의 연관 컨테이너들은 **동등성**에 기반을 두고 있습니다. -------------------------------------------------------------------------------- /C++/스마트 포인터.md: -------------------------------------------------------------------------------- 1 | # 스마트 포인터 2 | 3 | 현대 C++에서는 3가지 스마트 포인터가 있습니다. `unique_ptr`, `shared_ptr`, `weak_ptr`. 이전에 `auto_ptr`도 있었지만 현재는 여러 오류의 문제로 인해 사용하지 않습니다. 4 | 5 | 6 | 7 | 보통은 각 3개의 설명을 간단히 한 뒤 점차 심층 질문으로 들어가게 됩니다. 때문에 **아래 항목들을 읽어보는걸 추천**합니다. 8 | 9 | - unique_ptr : 객체의 소유권을 1개만 가지게 함 10 | - shared_ptr : reference counting 방식으로 객체의 소유권을 공유하게 되며 이 카운트가 0이 되면 객체가 해제 11 | - weak_ptr : shared_ptr보다 약한 카운트를 사용해서 관리 12 | 13 | 14 | 15 | ## RAII 패턴 16 | 17 | C++에서 자주 사용되는 패턴으로 객체가 어떠한 경우에서든 사용되는 범위를 벗어나면 소멸자가 불린다는 점을 이용한 패턴입니다. 18 | 19 | 객체가 자원을 할당받는건 생성자에서, 해제하는걸 소멸자에서 관리해 줌으로서 만일 delete를 하지 않거나 오류 등의 문제로 인해 범위를 벗어난 경우 자동적으로 자원을 해제할 수 있게 하는 패턴입니다. 20 | 21 | 위 스마트 포인터들은 이 RAII 패턴에 기반해서 작성이 되었습니다. 22 | 23 | 24 | 25 | ## shared_ptr과 상호 참조(순환 참조) 26 | 27 | 만일 shared_ptr A, B가 있을때 이들이 서로를 참조하고 있다면 카운트가 1 이하로 떨어지지 않아 삭제되지 않는다는 문제가 있습니다. 28 | 29 | 때문에 객체 소멸에 연관을 하지 않는 약한 참조 카운트를 가지는 weak_ptr을 통해서 순환 참조 문제를 해결할 수 있습니다. 30 | 31 | 32 | 33 | ## weak_ptr을 만드는 법과 사용하는 법 34 | 35 | weak_ptr은 shared_ptr의 산호참조 문제로 인해 나온 만큼 shared_ptr이나 다른 weak_ptr을 통해서만 생성할 수 있습니다. 36 | 37 | 또한 weak_ptr을 사용하기 위해서는 이걸 shared_ptr로 변경한 뒤 사용해야 하며 직접적으로 사용할 수 없습니다. 따라서 이 과정에서 내부에 정의된 lock 함수를 사용하게 됩니다. 38 | 39 | ```c++ 40 | std::shared_ptr makeSharedPtr = wPtr1.lock(); 41 | if(makeSharedPtr) 42 | { 43 | // do something 44 | } 45 | ``` 46 | 47 | 만일 이미 객체가 소멸되었다면 lock은 빈 shared_ptr을 반환하며 이는 false로 형변환이 되기에 if 문을 통해서 체크할 수 있습니다. 48 | 49 | 50 | 51 | ## shared_ptr, weak_ptr과 제어블록 52 | 53 | 이들의 '참조 카운트'를 계산하기 위해서 **제어블록**을 하나 두고 이를 공유하면서 reference counting을 하게 됩니다. 이 제어블록에 weak_ptr을 위한 약한 참조 카운트도 있습니다. 54 | 55 | shared_ptr의 참조 카운트가 0이 되어 객체는 삭제되어도 제어 블록은 여전히 남아 weak_ptr에게 이 객체가 해제되었음을 알려주게 됩니다. 56 | 57 | 58 | 59 | ## shared_ptr과 제어블록 생성과 관련한 이야기 60 | 61 | 만일 아래 코드처럼 이후에 shared_ptr을 생성하면 이전에 생성한 shared_ptr과 참조 카운트가 맞지 않는 오류가 생기게 됩니다. 이러면 한 제어블록의 카운트가 0이 되면 객체가 반환되어 다른 shared_ptr은 dangling pointer를 가리키는 문제가 생기게 됩니다. 62 | 63 | ```c++ 64 | std::shared_ptr sptr1(new Some()); 65 | std::shared_ptr sptr2(p1); 66 | std::shared_ptr sptr3(p2); 67 | 68 | std::cout << sptr1.use_count(); // 2 69 | std::cout << sptr2.use_count(); // 3 70 | std::cout << sptr3.use_count(); // 3 71 | ``` 72 | 73 | 때문에 제어블록을 통일할 필요가 있습니다. 74 | 75 | 76 | 77 | 제어블록은 **shared_ptr에 주소값(객체)를 넘겨주면 생성**됩니다. 이로 인해서 shared_ptr을 만들 때는 주소값을 통해서 만드는걸 최대한 지양해야 하며 어쩔 수 없는 경우를 위해 `enable_shared_from_this`를 통해 해결하게 됩니다. 78 | 79 | ```c++ 80 | class Some : public std::enable_shared_from_this { 81 | int *data; 82 | 83 | public: 84 | //... 85 | 86 | std::shared_ptr get_shared_ptr() { return shared_from_this(); } 87 | }; 88 | 89 | //... 90 | std::shared_ptr pa1 = std::make_shared(); 91 | std::shared_ptr pa2 = pa1->get_shared_ptr(); 92 | ``` 93 | 94 | `enable_shared_from_this`를 상속받으면 shared_from_this 함수가 있는데 이를 통해서 이미 있는 제어블록을 통해 shared_ptr을 만들 수 있게 됩니다. -------------------------------------------------------------------------------- /C++/얕은복사와 깊은복사.md: -------------------------------------------------------------------------------- 1 | ## 얕은 복사 / 깊은 복사 2 | 3 | - 얕은 복사 : 멤버의 값들만 복사합니다. 4 | 5 | - 깊은 복사 : 얕은 복사 + 객체가 가리키고 있는 포인터가 참조하는 대상까지 함께 복사합니다. 6 | 7 | 8 | 9 | --- 10 | 11 | 12 | 13 | C# 의 경우에는 참조만 복사하는게 얕은 복사로 되어 있어 C#을 했던 사람이라면 헷갈릴 수 있는 부분입니다. 14 | 15 | C# 에서는 16 | 17 | - 얕은 복사 : 객체에 대한 참조만을 생성해 결국 같은 힙 메모리를 참조하게 됩니다. 18 | 19 | - 깊은 복사 : 객체 복사 시 힙 메모리에 새로 할당을 해 완전 다른 객체가 만들어 집니다. 20 | -------------------------------------------------------------------------------- /C++/오버로딩 오버라이딩.md: -------------------------------------------------------------------------------- 1 | ## Overloading / Override 2 | 3 | - `오버로딩 (Overloading)` : 같은 이름의 함수에 인자를 다르게 해 다른 함수가 실행되게 하는 것 4 | 5 | - `오버라이드(Override)` : 상속 관계에서 부모 클래스의 가상 함수를 자식 클래스에서 재정의 하는 작업 6 | 7 | ### 오버로딩 특징 8 | 9 | 오버로딩이 가능한 조건은 아래와 같습니다. 10 | 11 | - `함수명`이 같은 경우 12 | 13 | - `리턴 타입`이 같은 경우 14 | 15 | - 인자의 종류, 갯수가 달라 구분이 되는 경우 16 | 17 | - 인자의 이름만 다르다면 오버로딩 불가능 (같은 함수로 처리해 컴파일 불가능) 18 | 19 | - 인자의 const성으로 구분은 **포인터 종류**만 가능 20 | 21 | ```cpp 22 | void Func(int& a) 23 | { 24 | cout << "normal reference a"; 25 | } 26 | void Func(const int& a) 27 | { 28 | cout << "const reference a"; 29 | } 30 | void Func(int* a) 31 | { 32 | cout << "normal pointer a"; 33 | } 34 | void Func(const int* a) 35 | { 36 | cout << "const pointer a"; 37 | } 38 | void Func(int a) 39 | { 40 | cout << "just a"; 41 | } 42 | // void Func(const int a) 43 | // { 44 | // cout << "const a"; 45 | // } //! ERROR 46 | ``` 47 | 48 |        위에서 일반 변수로 들어온 a 의 경우 const 유무에 상관 없이 복사를 하기 때문에 const로 받는지 아닌지를 판단해야할 이유가 없습니다. 함수 외부의 변수가 영향을 받을 일이 없기 때문이죠. 49 | 50 |         단 포인터나 참조의 경우에는 이게 const인지 아닌지에 따라서 함수 외부 값이 변경될 우려가 있기에 const 유무에 따른 오버로딩을 지원하게 되는 것입니다. 51 | 52 | ### 오버라이드 특징 53 | 54 | - 함수에 없던 const성을 파생 클래스에서 재정의할 수 없다 55 | 56 | ```cpp 57 | class Base 58 | { 59 | public: 60 | virtual void Print(int a) { cout << a; } 61 | }; 62 | class Derived : public Base 63 | { 64 | public: 65 | // ERROR!!ERROR!!ERROR!!ERROR!! 66 | virtual void Print(const int a) const override { cout << a; } 67 | }; 68 | ``` 69 | 70 | - 파생 클래스에서 인자에 const를 붙일 수 있다 71 | 72 | ```cpp 73 | class Base 74 | { 75 | public: 76 | virtual void Print(int a) { cout << "Base\n"; } 77 | }; 78 | class Derived : public Base 79 | { 80 | public: 81 | virtual void Print(const int a) override { cout << "Derived\n"; } 82 | }; 83 | ``` 84 | 85 | - 함수 인자의 기본값은 파생 클래스에서 재정의 할 수 없다 86 | 87 | ```cpp 88 | #include 89 | using namespace std; 90 | 91 | class Base 92 | { 93 | public: 94 | virtual void Print(int a = 1) { cout << a; } 95 | }; 96 | class Derived : public Base 97 | { 98 | public: 99 | virtual void Print(const int a = 3) override { cout << a; } 100 | }; 101 | 102 | int main() 103 | { 104 | Base* b1 = new Base(); 105 | Base* b2 = new Derived(); 106 | 107 | b1->Print(); // 1 108 | b2->Print(); // 1 109 | 110 | } 111 | 112 | ``` 113 | -------------------------------------------------------------------------------- /C++/포인터와 배열의 차이.md: -------------------------------------------------------------------------------- 1 | # 포인터와 배열의 차이 2 | 3 | 배열도 연속적인 원소들의 첫 주소를 가리키고 있다는 점에서 포인터라고 할 수 있습니다. 4 | 5 | 다만 배열의 경우 상수로 되어 있어 여러 연산이 되지 않지만 포인터 변수의 경우에는 증감 연산자, 대입 연산자 등이 사용 가능하게 됩니다. -------------------------------------------------------------------------------- /DB/Key.md: -------------------------------------------------------------------------------- 1 | ## Key 2 | 3 | ### 후보키 4 | 5 | 기본키가 될 수 있는 키들을 의미하며 아래 2가지 조건을 만족합니다. 6 | 7 | - 유일성 : 이 Key로 하나의 튜플을 뽑아낼 수 있습니다. 8 | 9 | - 최소성 : 필요한 속성만 있음 10 | 11 | ### 기본키 12 | 13 | 후보키에서 선택한 키로 Main이 됩니다. 이로 인해 중복될 수 없고 NULL 값을 가질 수 없습니다. 14 | 15 | ### 대체키 16 | 17 | 후보키 집합에서 기본키를 제외한 나머지 것들을 의미합니다. 18 | 19 | ### 슈퍼키 20 | 21 | 위 후보키의 특징 중에서 유일성은 만족하지만 최소성은 만족하지 못한 키들을 말합니다. 22 | 23 | > 예) 이름과 나이를 묶어 릴레이션에서 사람을 구분할 수 있는 경우 24 | 25 | ### 외래키 26 | 27 | 릴레이션 A, B의 관계에서 A 릴레이션이 참조하는 B 릴레이션의 기본키(하지만 A 릴레이션에 있는)를 의미합니다. 28 | 29 | 릴레이션간 관계를 나타내는데 사용할 수 있다고 합니다. 30 | -------------------------------------------------------------------------------- /DB/정규형.md: -------------------------------------------------------------------------------- 1 | ## 정규형 2 | 3 | ### 정규화란? 4 | 5 | 함수 종속성을 이용해 릴레이션을 연관성이 있는 속성들로만 구성되도록 분해하는 작업으로 이상현상이 없는 바른 릴레이션으로 만드는 것이 목표입니다. 6 | 7 | 여기서 정규화를 한 후 릴레이션은 손실 없이 분해가 되어야 하며 분해된 릴레이션들은 자연조인을 했을 시 분해 전으로 복원 가능해야 합니다. 8 | 9 | > 기본 정규형(1, 2, 3, 보이스/코드)과 고급 정규형(4, 5) 가 있습니다. 대부분의 내용은 기본 정규형으로 다루도록 하겠습니다. 10 | 11 | ### 제 1 정규형 12 | 13 | 각 칼럼이 하나의 속성만을 가지게 해야 합니다. 14 | 15 | | ID | EVENTNUM | 16 | | --- | -------- | 17 | | Wow | 1, 2, 4 | 18 | 19 | 위에서는 EventNum에 1, 2, 4가 있어 제 1 정규형을 만족하지 않습니다. 20 | 21 | | ID | EVENTNUM | 22 | | --- | -------- | 23 | | Wow | 1 | 24 | | Wow | 2 | 25 | | Wow | 4 | 26 | 27 | 이런 식으로 분리해야 합니다. 28 | 29 | ### 제 2 정규형 30 | 31 | 제 1 정규형에 속하고 **기본키가 아닌 속성이 모두 기본키에 완전 종속되는 경우**를 이야기 합니다. 32 | 33 | | ID | EVENTNUM | GRADE | PERCENT | 34 | | ----- | -------- | ----- | ------- | 35 | | Wow | 1 | P | 20% | 36 | | Wow | 2 | P | 20% | 37 | | Great | 7 | G | 10% | 38 | 39 | 라는 릴레이션이 있을 때 `부분 함수 종속성`을 제거해야 합니다. 40 | 41 | | ID | EVENTNUM | 42 | | ----- | -------- | 43 | | Wow | 1 | 44 | | Wow | 2 | 45 | | Great | 7 | 46 | 47 | | ID | GRADE | PERCENT | 48 | | ----- | ----- | ------- | 49 | | Wow | P | 20% | 50 | | Great | G | 10% | 51 | 52 | 이런 식으로 모든 속성이 기본키에 완전 종속되게 변경해주는게 제 정규화 작업입니다. 53 | 54 | ### 제 3 정규형 55 | 56 | 제 3 정규형은 제 2 정규형에서 `이행적 함수 종속`을 제거한 것입니다. 57 | 58 | | ID | GRADE | PERCENT | 59 | | ----- | ----- | ------- | 60 | | Wow | P | 20% | 61 | | Great | G | 10% | 62 | 63 | 위 제 2 정규형을 거친 릴레이션에서 문제는 `이행적 함수 종속`이 있다는 것입니다. 64 | 65 | > `이행적 함수 종속` 이란 릴레이션을 구성하는 속성 X, Y, Z 에서 X > Y, Y > Z 이면 X > Z 가 되는데 이 경우 Z가 X에 이행적으로 함수 종속되었다고 합니다. 66 | 67 | 위 릴레이션에서는 ID를 통해 GRADE를 알 수 있고 GRADE 에서 PERCENT를 알 수 있습니다. 때문에 이들을 분해하는 작업이 필요합니다. 68 | 69 | | ID | GRADE | 70 | | ----- | ----- | 71 | | Wow | P | 72 | | Great | G | 73 | 74 | | GRADE | PERCENT | 75 | | ----- | ------- | 76 | | P | 20% | 77 | | G | 10% | 78 | 79 | 이렇게 ID로 GRADE 만을 알 수 있고 GRADE로 PERCENT를 알 수 있습니다. 80 | 81 | ### 보이스 코드 정규형 - BCNF (Boyce Codd Normal Form) 82 | 83 | 제 3 정규형에서 더 나아가 **모든 결정자가 후보키**라면 BCNF를 만족하게 됩니다. 84 | 85 | | ID | SHOP | SHOP MANAGER | 86 | | ----- | ---- | ------------ | 87 | | Wow | GS35 | Tom | 88 | | Great | FU | Hardy | 89 | 90 | 여기서 기본키는 ID 와 SHOP이 됩니다. ID를 담당하는 SHOP MANAGER가 있어야 하고 SHOP을 관리하는 SHOP MANAGER가 있는 것입니다. 91 | 92 | 이런 경우가 있다면 만일 Wow 고객이 FU로 가게를 변경했음에도 SHOP MANAGER가 그대로 있어 데이터 불일치가 있을 수 있으며 삽입, 삭제 시에도 신경써야 할 부분이 늘어나게 됩니다. 93 | 94 | 역시나 해결법은 분리를 하는 것입니다. 95 | 96 | | ID | SHOP | 97 | | ----- | ---- | 98 | | Wow | GS35 | 99 | | Great | FU | 100 | 101 | | SHOP MANAGER | SHOP | 102 | | ------------ | ---- | 103 | | Tom | GS35 | 104 | | Hardy | FU | 105 | 106 | 이런식으로 분리를 하면 됩니다. 107 | 108 | ### 제 4, 5 정규형 109 | 110 | - 제 4 정규형 : BCNF 를 만족하면서 함수 종속이 아닌 다치 종속을 제거하면 만족 111 | 112 | - 제 5 정규형 : 제 4 정규형을 만족하면서 후보키를 통하지 않는 조인 종속을 제거하면 만족 113 | -------------------------------------------------------------------------------- /DesignPattern/AdapterPattern.md: -------------------------------------------------------------------------------- 1 | # 어댑터 패턴 (Adapter Pattern) 2 | 3 | > 현실의 플러그 변환기를 떠올리면 쉽습니다. 4 | 5 | 어댑터 패턴은 클래스의 인터페이스를 클라이언트에 맞춰주는 패턴입니다. 6 | 7 | ![제목 없는 다이어그램 drawio (1)](https://user-images.githubusercontent.com/68003176/209071321-7bcd8cc9-f385-46d2-bc47-289aece8be8b.png) 8 | -------------------------------------------------------------------------------- /DesignPattern/FacadePattern.md: -------------------------------------------------------------------------------- 1 | # 퍼사드 패턴 (Facade Pattern) 2 | 3 | 퍼사드 패턴의 주 사용처는 '객체 그룹에 간단하지만 구체적인 인터페이스'를 제공하는 경우 입니다. 4 | 5 | ![Facade UML from Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/UML_DP_Fa%C3%A7ade.png/220px-UML_DP_Fa%C3%A7ade.png) 6 | 7 | 위 UML의 예시로 퍼사드가 '물건 구매' 인터페이스를 가진다고 합시다. 사용자(클라이언트)는 단순히 '물건 구매' 인터페이스를 호출하기만 하면 되는 것이고 퍼사드 패턴 안에서는 하위 클래스들을 조합해 사용자가 알 수 없게 일을 잘 처리하는 과정을 거치게 됩니다. 뭐 퍼사드는 창고에서 물건 꺼내오기, 송장번호 붙이기, 발송지로 보내기, 배달의 과정을 거치게 되겠죠. 8 | 9 | ## 퍼사드 패턴의 장단점 10 | 11 | - 장점 12 | - 복잡한 시스템으로부터 간단한 인터페이스를 만들 수 있습니다. 13 | - 인터페이스의 분리를 통해 클라이언트와 실제 역할을 하는 클래스간 결합도를 낮출 수 있습니다. 14 | - 단점 15 | - 퍼사드 클래스가 지나치게 비대해 질 경우 유지보수가 좋지 않습니다. 16 | - 사용자에게 하위 클래스(일을 하는 클래스)를 완전히 숨길 수는 없습니다. 17 | 18 | ## 자료 출처 19 | - [Facade UML Image, Example Idea](https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%82%AC%EB%93%9C_%ED%8C%A8%ED%84%B4) -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern.md: -------------------------------------------------------------------------------- 1 | # 널 오브젝트 패턴 2 | 3 | 객체를 활용하는 경우에 어디선가 객체를 구해오면 이게 null인지 아닌지를 체크할 필요가 있습니다. 이 경우 코드가 상당히 보기 싫어지게 됩니다. 4 | 5 | 때문에 이런 경우에 객체를 반환하는 함수에서 null을 반환하는게 아닌 null과 의미가 유사한 `널 오브젝트`를 반환하는 것입니다. 6 | 7 | 이 반환되는 `널 오브젝트`는 실제로 null이 아닌 객체지만 **하는 일은 없는 객체**를 의미합니다. 만일 경험치를 줘야 하는 객체인데 NullExp 객체를 반환하면 경험치를 주지 않는 작업을 한다고 합시다. 8 | 9 | ```cs 10 | Exp exp = DB.GetMonsterExp("MonsterName"); 11 | if(exp != null) 12 | { 13 | exp.GiveExpToPlayer(player); 14 | } 15 | ``` 16 | 17 | 이런 코드에서 널 오브젝트 패턴을 활용하면 18 | 19 | ```cs 20 | Exp exp = DB.GetMonsterExp("MonsterName"); 21 | // NullExp 객체는 아무 일도 안하기에 플레이어에게 경험치를 주지 않는다 22 | exp.GiveExpToPlayer(player); 23 | ``` 24 | 25 | 이런 식으로 코드를 짧게 가져갈 수 있다는 것입니다. 즉, null 여부를 검사하지 않는 코드를 만들 수 있는 것이죠. -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern.md: -------------------------------------------------------------------------------- 1 | # 옵저버 패턴 (Observer Pattern) 2 | 3 | 옵저버 패턴은 객체의 상태 변화를 관찰하는 옵저버들을 두어 변화가 있을 때마다 객체가 옵저버들에게 메소드 등으로 통지하는 패턴입니다. 4 | 변화가 있는 객체에서 옵저버 리스트를 두어 변화가 있을 때 리스트에 있는 옵저버들을 호출하게 됩니다. 5 | 6 | ![제목 없는 다이어그램 drawio (2)](https://user-images.githubusercontent.com/68003176/209293328-73123166-c4dd-4d6d-83ad-86051c7032fb.png) 7 | 8 | UML을 참고하면 호출 흐름이 Subject -> Observer로 흘러가는걸 알 수 있습니다. 인터페이스나 델리게이트 등으로 콜백을 만들어 사용하는 방식입니다. 9 | 10 | ## 옵저버 패턴의 장단점 11 | - 장점 12 | - 객체와 옵저버간 결합이 느슨해집니다. 13 | - 직관적인 이해가 쉽습니다. 14 | - 단점 15 | - 멀티스레드 환경에서 등록/취소 작업과 실행 작업이 겹칠 수 있어 결과가 비틀어질 수 있습니다. 16 | - 너무 많은 옵저버가 있는 경우 시간이 느려지기도 하고 상태 관리가 힘들다 -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern.md: -------------------------------------------------------------------------------- 1 | # 프록시 패턴 (Proxy Pattern) 2 | 3 | > Proxy : 대리인, 대리권, 대리 4 | 5 | `프록시`는 클래스를 이어주는 대리인 역할을 하는 클래스 입니다. 이를 활용한게 프록시 패턴인 것이죠. 6 | 7 | ![Proxy UML from Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Proxy_pattern_diagram.svg/400px-Proxy_pattern_diagram.svg.png) 8 | 9 | 위 UML에서 객체 사용시 객체를 직접 호출하는게 아닌 프록시 클래스를 부르게 되고 프록시는 실제 역할을 하는 클래스에게 처리를 요구하는 패턴인 것입니다. 10 | 11 | ## 프록시 패턴의 장단점 12 | - 장점 13 | - 실제 일을 하는 클래스와 구분 지을 수 있음 14 | - 사이즈가 큰 객체가 있을 시 로딩 전에 프록시 객체를 통해 참조 가능 15 | - 단점 16 | - 로직이 복잡해지면서 코드 읽기가 좋지 않을 수 있습니다. 때문에 가급적 다른 해결법을 찾는게 좋습니다. 17 | - 객체 생성시 단계가 늘어나게 됩니다. 이로 인해서 빈번한 생성, 삭제에서는 메모리가 무거워 집니다. 18 | 19 | ## C++의 `vector`, 스마트 포인터도 프록시 패턴이다 20 | 21 | [c++ vector 문서 참고](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/vector%EC%99%80%20%EA%B4%80%EB%A0%A8%ED%95%9C%20%EC%9D%B4%EC%95%BC%EA%B8%B0%EB%93%A4.md) 22 | 23 | 스마트 포인터의 경우에는 일반 포인터의 인터페이스를 유지할 수 있으면서 작업을 하게 됩니다. (operator ->, * 를 사용할 수 있는 점 등) 24 | 25 | 26 | 27 | ## 자료 출처 28 | - [Proxy UML Image](https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%ED%8C%A8%ED%84%B4) -------------------------------------------------------------------------------- /DesignPattern/SingletonPattern.md: -------------------------------------------------------------------------------- 1 | # Singleton Pattern 2 | 3 | 싱글톤 패턴은 많이 사용하는 경우가 많지만 필연적으로 '멀티스레드에서 어덯게 활용해왔나' 라는 질문이 따라오게 됩니다. 때문에 관련 경험이나 지식이 없어 자신있게 대답할 수 없다면 가급적 다른 디자인 패턴으로 질문을 유도하는게 좋습니다. 4 | 5 | ## 싱글톤 패턴의 정의 6 | 7 | `싱글톤 패턴(Singleton Pattern)`은 클래스의 인스턴스를 한개만 가지게 하는 디자인 패턴입니다. 8 | 유니티의 C#에서는 이를 간단하게 제작할 수 있습니다. 9 | ```cs 10 | public SingletonClass : Monobehaviour 11 | { 12 | public static SingletonClass instance; 13 | 14 | private void Awake() 15 | { 16 | if(instance == null) 17 | { 18 | instance = this; 19 | } 20 | else 21 | { 22 | Destroy(this); 23 | } 24 | } 25 | } 26 | ``` 27 | 28 | C++ 에서는 생성자를 private에 넣고 이를 사용하게 됩니다. 또한 대입, 복사와 관련한 연산을 삭제해주게 됩니다. 29 | ```cpp 30 | class SingletonClass 31 | { 32 | public: 33 | static Singleton& GetInstance() { 34 | static Singleton* singleton = new Singleton(); 35 | return *singleton; 36 | } 37 | 38 | private: 39 | SingletonClass() = default; 40 | 41 | SingletonClass(const SingletonClass&) = delete; 42 | SingletonClass& operator=(const SingletonClass&) = delete; 43 | SingletonClass(SingletonClass&&) = delete; 44 | SingletonClass& operator=(SingletonClass&&) = delete; 45 | }; 46 | 47 | // code from Wikipedia 48 | ``` 49 | 50 | ## 싱글톤 패턴의 사용 이유, 장점 51 | 52 | 일단 싱글톤 패턴을 활용한 클래스의 생명주기는 프로그램의 생명주기와 같게 됩니다. 프로그램이 메모리에 올라감과 동시에 함께 올라가고 프로그램이 종료될 때 사라지게 됩니다. 53 | 이런 점을 이용해 메모리에 한번만 올라간다는 특징 덕분에 여러 인스턴스의 생성을 통한 메모리 사용을 막을 수 있습니다. 54 | 또한 전역으로 메모리에 올라가기에 다른 인스턴스들에서도 자유롭게 접근이 가능하다는 장점이 있습니다. 55 | 56 | 57 | ## 싱글톤 패턴의 단점 58 | 59 | 이러니 저러니 해도 계속 메모리에 올라가 있어 사용하지 않을떄도 메모리를 점유한다는 단점이 있습니다. 또한 소멸에 대한 부분이 정의되지 않기에 C++ 환경에서 사용할 때 소멸된 객체에 대한 역참조 문제가 있을 수도 있습니다. 그리고 이 싱글톤 인스턴스가 null인지 항상 체크하게 되는 비효율성이 있을 수 있죠. 60 | 61 | 가장 큰 문제는 동시성 문제입니다. 멀티스레드 환경에서 인스턴스가 2개 생기는 경우도 있고 여러 스레드에서 참조할 때 동기화 처리를 해줘야 하는 번거로움이 있습니다. 이로 인해 버그 탐색도 어려워지게 됩니다. 62 | 63 | > 멀티 스레드 환경에서 싱글톤 패턴 사용 경험에 대한 질문이 많습니다. -------------------------------------------------------------------------------- /DesignPattern/StatePattern.md: -------------------------------------------------------------------------------- 1 | # 스테이트 패턴 (State Pattern) 2 | 3 | > 이 패턴을 알기 위해서는 FSM에 대한 지식이 있어야 합니다. 4 | 5 | 한번에 한 상태만 가질 수 있는 FSM을 제작할 떄 많이 사용하게 되는 패턴입니다. 중첩 switch/case 문으로 구현할 수 있지만 상태가 많아질수록 이는 확장성이 떨어지기 떄문에 스테이트 패턴으로 구현할 수 있습니다. 6 | 7 | ![좀비의 FSM을 구현한다면](https://user-images.githubusercontent.com/68003176/208879792-cdc3fbf2-069b-48c7-a975-ed53367093dd.png) 8 | 9 | 10 | 상위 인터페이스인 State 에서는 관련 기능들에 대한 함수들을 준비하고 상속받는 파생 State들에서는 해당 State에서 할 수 있는 함수를 구현하는 것이죠. 11 | 12 | ## 전략 패턴과의 차이 13 | 14 | 스테이트 패턴은 전략 패턴과 비슷한 모습을 하게 됩니다. 일단 유래가 스테이트 패턴은 조건문을 대체하는 것이고 전략 패턴은 상속을 대체할 수 있도록 나온 것입니다. 15 | 16 | 또한 스테이트 패턴에서는 State들의 파생 클래스들이 일을 하는 Context 클래스에 대한 참조를 가지고 있다는 차이를 가지고 있습니다. 대신 전략 패턴은 이런 경우가 없죠. 17 | 18 | 때문에 **스테이트 패턴은 전부 전략 패턴이 될 수 있는데 전략 패턴은 전부 스테이트가 될 수는 없습니다.** -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern.md: -------------------------------------------------------------------------------- 1 | # 스트래터지(전략) 패턴 (Strategy Pattern) 2 | 3 | `스트래터지 패턴`은 인터페이스를 통해 특정 행동들을 인터페이스로 묶고 이를 교환하면서 사용하는 패턴입니다. 4 | 5 | 게임을 예시로 만일 캐릭터의 무기가 총, 칼이 있다고 하면 아래처럼 전략 패턴을 활용할 수 있습니다. 6 | 7 | ```cpp 8 | // IWeapon.h 9 | class IWeapon 10 | { 11 | public: 12 | virtual void Attack() = 0; 13 | }; 14 | 15 | // Player.h 16 | class Player 17 | { 18 | IWeapon* Weapon; 19 | 20 | //... 만약 공격 키가 눌리면 21 | Weapon->Attack(); 22 | }; 23 | 24 | class Sword : public Weapon 25 | { 26 | virtual void Attack() override 27 | { 28 | //.. 검을 휘두른다 29 | } 30 | }; 31 | 32 | class Gun : public Weapon 33 | { 34 | virtual void Attack() override 35 | { 36 | //.. 총을 쏜다 37 | } 38 | }; 39 | ``` 40 | 41 | ## UML 42 | 43 | ![Strategy drawio](https://user-images.githubusercontent.com/68003176/208416998-353692a8-d9dc-4de6-a2bf-b1ded1fe734e.png) 44 | 45 | 46 | 47 | 이런 식으로 플레이어가 무기를 변경한다고 해도 무기들의 `IWeapon`의 정의만 알고 있으면 플레이어의 코드 변경 없이 교체가 가능합니다. 48 | 즉, 구체적인 클래스와 알고리즘 사이의 결합도를 낮추는 디자인 패턴으로 구체 클래스를 수정하는 일이 줄어드는, 유지보수에 도움이 되는 디자인 패턴입니다. 49 | 50 | 51 | 52 | ## 스트래터지 패턴은... 53 | 사실 바로 정의를 이야기 하기 보다는 이를 활용한 본인의 프로젝트 예시를 드는게 좋아 보입니다. -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | /* 2 | * ----------------------------------------------------------------- 3 | * "THE BEERWARE LICENSE" (Revision 42): 4 | * As long as you retain this notice, 5 | * you can do whatever you want with this stuff. 6 | * If we meet someday, and you think this stuff is worth it, 7 | * you can buy me a beer in return. 8 | * 9 | * 이 리포지토리는 Beerware 라이센스를 가집니다. 10 | * 특별한건 없고 혹시나 이 리포지토리의 내용이 마음에 들었고 유용했다면 11 | * 다음에 만날때 맥주 한잔 사주세요. 12 | * ----------------------------------------------------------------- 13 | */ 14 | -------------------------------------------------------------------------------- /OOP/객체지향5원칙.md: -------------------------------------------------------------------------------- 1 | # 객체지향 프로그래밍 제 5원칙 2 | 객체지향 프로그래밍은 소프트웨어 개발 방법론 중 하나로, 프로그램을 독립적인 객체들로 구성하여 문제를 해결하는 방식입니다. 객체지향 프로그래밍의 핵심 원칙은 "SOLID" 원칙으로 알려져 있는 다섯 가지 원칙입니다. 각 원칙은 소프트웨어 설계의 품질과 유지보수성을 향상시키기 위해 따라야 할 지침을 제공합니다. 3 | 4 | - 단일 책임 원칙 (Single Responsibility Principle, SRP): 5 | 6 | 객체는 단 하나의 책임만을 가져야 합니다. 7 | 어떤 변화에 의해 수정되어야 하는 이유는 오직 하나뿐이어야 합니다. 8 | 한 클래스는 하나의 주요 기능 또는 책임을 갖도록 설계되어야 합니다. 9 | 10 | 11 | - 개방-폐쇄 원칙 (Open-Closed Principle, OCP): 12 | 13 | 소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 합니다. 14 | 즉, 기존의 코드를 수정하지 않고도 새로운 기능을 추가할 수 있도록 설계되어야 합니다. 15 | 16 | 17 | - 리스코프 치환 원칙 (Liskov Substitution Principle, LSP): 18 | 19 | 자식 클래스는 언제나 부모 클래스의 역할을 대체할 수 있어야 합니다. 20 | 즉, 부모 클래스를 사용하는 코드는 자식 클래스로 대체해도 정상적으로 동작해야 합니다. 21 | 22 | 23 | - 인터페이스 분리 원칙 (Interface Segregation Principle, ISP): 24 | 25 | 클라이언트 필요하지 않는 기능을 의존하도록 강요하지 않는 원칙입니다. 26 | 클라이언트가 필요로만 하는 기능을 인터페이스로 분리합니다. 그리고 그 인터페이스로 의존하는 방법으로 불필요한 재컴파일과 의존을 막을 수 있습니다. 27 | 28 | 29 | - 의존성 역전 원칙 (Dependency Inversion Principle, DIP): 30 | 31 | 상위 수준의 모듈은 하위 수준의 모듈에 의존하면 안된다. 32 | 둘 모두 추상화에 의존해야 합니다. 33 | 추상화는 구체적인 사항에 의존해서는 안된다. 구체적인 사항은 추상화에 의존해야 한다. 34 | 추상화된 인터페이스나 추상 클래스를 통해 상호작용하도록 설계되어야 합니다. 35 | 36 | 37 | 38 | #### 객체지향 5원칙인 SOLID 원칙은 소프트웨어의 유지보수성, 재사용성, 확장성 등을 향상시키는 기준으로 사용되며, 객체지향 설계의 중요한 지침을 제공합니다. 이러한 원칙을 따르면 코드의 가독성과 유지보수성을 향상시킬 수 있습니다. 39 | -------------------------------------------------------------------------------- /OS/CPU 스케쥴러의 알고리즘 종류.md: -------------------------------------------------------------------------------- 1 | # CPU 스케쥴러의 알고리즘 종류 2 | 3 | 4 | 5 | ## FCFS - First Come First Served 6 | 7 | 간단하게 먼저온 순으로 진행해 주는 것입니다. Non preemptive라서 현재 진행중인 프로세스를 종료할 수단이 없습니다. 8 | 9 | 10 | 11 | ## SJF - Shortest Job First 12 | 13 | 말 그대로 현재 시점에서 짧은 일을 먼저 처리하는 것입니다. 이 중에서도 Preemptive, Non preemptive가 존재합니다. Non preemptive의 경우에는 현재 실행하는 프로세스를 종료하지 않으며 Preemptive의 경우에는 현재 사용하는 프로세스보다 새 프로세스의 시간이 더 짧으면 교체하게 됩니다. 14 | 15 | 16 | 17 | > **어떻게 프로세스의 시간을 알 수 있을까?** 18 | 19 | 프로세스를 실행하지 않고 시간을 정확히 알 수 없으니 '예측'을 하게 됩니다. 이 예측은 이전 프로세스의 '예상 수행시간'과 '실제 수행시간'을 기반으로 예측하게 됩니다. 20 | 21 | - (N번째의 CPU 사용 예측치) = (적응속도) \* (N-1 프로세스의 실제 시간) + (1 - 적응속도) \* (N-1 프로세스 예측 시간) 22 | - 여기서 적응 속도는 0~1의 값을 가지고 0이 될수록 이전 예측에 좀 더 가중치를 주겠다는 이야기입니다. 23 | 24 | 25 | 26 | ## Priority - 우선순위 스케쥴링 27 | 28 | 각 프로세스에 우선순위를 부여하고 이 우선순위가 높을수록 먼저 CPU에 할당해 줍니다. 위 SJF의 경우에는 우선순위 스케쥴링의 일종으로 짧은 시간이라 예측된 프로세스에 우선도를 주는 형식입니다. 29 | 30 | 문제점은 우선순위가 낮은 프로세스는 우선순위가 높은 프로세스가 계속 들어온다면 계속 실행되지 못할 수도 있습니다. 이걸 기아(Starvation)문제라고 합니다. 이를 해결하기 위해서는 aging 기법을 활용해 시간이 흐를 때 우선순위를 높여줘야 합니다. 31 | 32 | 33 | 34 | ## RR - Round Robin 35 | 36 | 일전 시간을 정한 뒤 이 시간이 지나면 **프로세스 완료 여부와 관계 없이 종료하고 다른 프로세스로 교체**하는 것입니다. 만일 시간 단위가 q 라고 하고 N개의 프로세스가 있다고 하면 각 프로세스가 (N-1)q보다 기다리는 경우는 없습니다. 37 | 38 | 39 | 40 | ## SRTF(Shortest Remaining Time First) 41 | 42 | 특징 43 | - 새로운 프로세스가 도착할 때마다 새로운 스케줄링이 이루어진다. 44 | - 선점형 (Preemptive) 스케줄링 45 | - 현재 수행중인 프로세스의 남은 burst time 보다 더 짧은 CPU burst time 을 가지는 새로운 프로세스가 도착하면 CPU 를 뺏긴다. 46 | 47 | 문제점 48 | - starvation 49 | - 새로운 프로세스가 도달할 때마다 스케줄링을 다시하기 때문에 CPU burst time(CPU 사용시간)을 측정할 수가 없다. 50 | -------------------------------------------------------------------------------- /OS/DeadLock (데드락, 교착 상태, 이하 데드락).md: -------------------------------------------------------------------------------- 1 | # DeadLock (데드락, 교착 상태, 이하 데드락) 2 | 3 | 데드락는 공유 자원에 대해서 타 프로세스가 선점한 자원을 필요로 하고 그 선점한 프로세스도 타 프로스세의 선점 자원을 원해 서로 무한정 기다리게 되는 것입니다. 4 | 5 | 6 | 7 | > 간단한 비유를 하자면 수저가 있고 두 사람이 각각 숟가락, 젓가락을 나눠 가졌습니다. 8 | > 9 | > 밥을 먹기 위해서는 수저를 완성해야 하는데 이 둘은 각자의 도구를 놓을 생각이 없기에 서로 밥을 못먹게 되는 이야기 입니다. 10 | 11 | 12 | 13 | ## 데드락의 발생 조건 14 | 15 | 데드락의 경우 아래 4 조건이 동시에 지켜지면 발생하게 됩니다. 16 | 17 | - 공유 자원에 대한 상호 배제를 하고 있을 때 18 | - 추가적인 자원을 위해 기다리고 있을 때 19 | - 선취 불가능(No Preemptive) 20 | - 다른 프로세스 종료가 안되는 경우 21 | - 자원 관계에 있어서 사이클이 있을 때 22 | - 원하는 자원 -> 가지는 프로세스로 그래프를 그릴 때 사이클이 있는 경우 23 | 24 | 특히 위 '상호 배제'는 반드시 지켜야 하는 부분입니다. 25 | 26 | 27 | 28 | ## 데드락 방지, 해결 29 | 30 | 위 `데드락 발생 조건` 4가지중 1개라도 사라지면 해결이 가능합니다. 다만 위에 언급한대로 1번, `상호배제`의 경우 제거하면 안됩니다. 때문에 남은 3개에 초점을 맞춰 해결을 하게 됩니다. 31 | 32 | 대부분의 경우 데드락을 방지하기 위해서 사이클이 발생하는걸 방지하는데 초점이 맞춰져 있습니다. 33 | 34 | 35 | 36 | 혹시나 데드락이 발생했을 경우에는 관련 프로세스를 전부 종료하거나 데드락이 사라질 때 까지 프로세스를 하나씩 중단하게 됩니다. 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /OS/가상 메모리 - Virtual Memory.md: -------------------------------------------------------------------------------- 1 | # 가상 메모리 - Virtual Memory 2 | 3 | 가상 메모리 기법은 실제 메모리보다 메모리가 더 많아 보이게 하는 기법입니다. 프로그램의 현재 실행에 필요한 부분만 메모리에 올라가고 나머지는 보조 기억장치(HDD, SSD 등)에 올려두고 사용하는 것입니다. 4 | 5 | 이런 과정을 위해 MMU(Memory Management Unit)이라는 장치가 필요하며 이 장치를 통해 논리 주소를 물리 주소로 변환할 수 있게 됩니다. 현대 CPU는 다 MMU가 내장되어 있습니다. 6 | 7 | 8 | 9 | ## Page Fault 10 | 11 | 가상 메모리 기법을 활용하면 필요한 페이지가 메모리에 없는(물리주소에 없는) page fault 가 발생하게 됩니다. 이 경우에 디스크에서 페이지를 불러오고 필요없는 페이지를 디스크로 보내는 Swap In/Out 작업을 하게 됩니다. 12 | 13 | 14 | 15 | ## Page Replacement 16 | 17 | 일단 위 Page fault로 인해서 디스크를 오가게 되는데 일단 이런 작업은 시간이 많이 들게 됩니다. 보조 기억장치는 일반적으로 메모리보다 느리기 때문입니다. 18 | 19 | 이런 시간을 최대한 줄이기 위해서 사용 가능성이 높은 페이지는 메모리에, 가능성이 적은 페이지는 디스크에 두는 정책이 필요하게 됩니다. 20 | 21 | - FIFO Page Replacement 22 | - 자료구조의 FIFO 처럼 선입선출, 가장 먼저 들어온 페이지를 교체해 줍니다. 23 | - 이 경우 [Belady's Anomaly](https://en.wikipedia.org/wiki/B%C3%A9l%C3%A1dy%27s_anomaly)이라는 문제가 생길 수 있다 24 | - 페이지의 프레임 수가 커질수록(사용 가능 메모리 크기가 커질때) Page Fault가 줄어드는걸 원하는데 역으로 늘어난다는 역설 25 | - 다른 Page Replacement 정책에는 없는 이야기입니다. 26 | - 간단한 만큼 그렇게 좋은 성능이 아닙니다. 27 | - Optimal Page Replacement 28 | - **가장 오랫동안 사용하지 않을 페이지를 내보내는 알고리즘**입니다. 29 | - 왜 굳이 볼드체를 했냐면 이건 아주 이상적인 알고리즘이기 때문입니다. 미래를 볼 수 없어 어떤 페이지가 오랫동안 사용되지 않을지 알 수 없습니다. 30 | - 때문에 가장 시간이 짧으며 타 알고리즘의 성능 측정용으로 많이 사용됩니다. 31 | - LRU (Least Recently Used) 32 | - 가장 오랫동안 사용하지 않은 페이지를 내보내는 알고리즘입니다. 33 | - 시간 기록을 위한 오버헤드가 있습니다 34 | - Second change page replacement algorithm (= colck algorithm)이란 방법이 추가적으로 있습니다. 35 | - 페이지별로 reference bit가 있어 0이면 안한것, 1이면 한 것입니다. 36 | - 시계방향으로 체크를 하면서 1일 경우 한턴을 넘기고 0으로 바꾼뒤 0이라면 이 페이지를 교체하는 방식입니다. 37 | 38 | - LFU (Least Frequency Used) 39 | - 가장 적게 사용한걸 내보내는 알고리즘입니다. 40 | 41 | 42 | 43 | ## TLB (Translation Lookaside Buffer) 44 | 45 | 위 물리 주소에 페이지를 두는 것에 관련한 이야기라면 이건 **주소를 관리하는**이야기 입니다. 46 | 47 | TLB는 실제 페이지 테이블 중 최근 값들을 저장하는 버퍼입니다. 최근에 사용되는 페이지들의 주소를 관리하면서 주소를 빨리 찾아갈 수 있게 하는 것입니다. 48 | 49 | 주소를 찾기 위해서는 일단 TLB에 접근 한 다음 TLB에 있다면 이를 통해 바로 접근, 없다면 MMU에서 주소를 변환한 후 메모리에 접근하게 됩니다. -------------------------------------------------------------------------------- /OS/리틀 앤디언, 빅 앤디언.md: -------------------------------------------------------------------------------- 1 | # 리틀 앤디언, 빅 앤디언 2 | 3 | 4 | 5 | ## 앤디언 (= 엔디안) 6 | 7 | 컴퓨터의 메모리 같은 1차원 연속 배열에서 원소들을 어떻게 배열하는지에 대한 방법 8 | 9 | 10 | 11 | ## 리틀 vs 빅 12 | 13 | | **빅 앤디언** | **리틀 앤디언** | 14 | | :----------------------------------------------------------: | :----------------------------------------------------------: | 15 | | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/Big-Endian.svg/200px-Big-Endian.svg.png) | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Little-Endian.svg/200px-Little-Endian.svg.png) | 16 | | 사람이 읽기 편한 방식으로 저장
사람 읽는 방식과 같아 디버깅이 편함
주로 네트워크 주소에 사용이 됩니다. | 작은 단위 바이트가 앞으로
아래 자리부터 보기 때문에 사칙연산에서 이점
x86 프로세서(컴퓨터)는 이 방식을 사용 | 17 | 18 | 19 | 20 | ## 추가 볼점 21 | 22 | 면접에서 앤디언에 대한 이야기는 'x86 프로세스는 어떤 앤디언일까요?' 정도로 간단하게 넘어가는 편인데 일단 추가적으로 볼만한 부분들을 아래 남겨보겠습니다. 23 | 24 | - 이 두가지 앤디언 외 다른건 없는가? 25 | - ARM 아키텍쳐는 어떤 엔디언을 사용하는가? 26 | - 성능 향상을 위해 리틀, 빅을 선택할 수 있다고 함 27 | 28 | 29 | 30 | ## 이미지 사진 출처 31 | 32 | [Wikipedia - Ko](https://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8) -------------------------------------------------------------------------------- /OS/메모리 단편화 - Memory Fragmentation.md: -------------------------------------------------------------------------------- 1 | # 메모리 단편화 - Memory Fragmentation 2 | 3 | 4 | 5 | ## 메모리 단편화란? 6 | 7 | 메모리 단편화는 **사용가능한 메모리는 충분히 있지만 이게 흩어져서 할당이 불가능한 경우**를 의미합니다. 종류는 **외부 단편화, 내부 단편화** 2가지가 있습니다. 8 | 9 | - 내부 단편화 10 | - 할당시 프로세스가 필요한 메모리보다 많은 메모리를 할당한 경우를 의미합니다. 11 | - 외부 단편화 12 | - 남은 전체 메모리는 충분히 있는데 이것들이 '연속된 공간'이 아니라 흩어져 있어 할당이 안되는 경우 13 | 14 | 15 | 16 | ## 메모리 단편화 해결법 17 | 18 | ### 외부 단편화 해결법 19 | 20 | - 페이징 21 | - 페이징 기법은 보조 기억장치(디스크, SSD 등)를 메모리처럼 구역을 나눈 뒤 필요한 부분을 메모리로 옮겨서 사용하는 걸 의미합니다. 22 | - 여기서 **Page, 페이지는 프로세스를 일정한 크기로 나눈걸 의미**합니다. 23 | - 이 과정에서 첫 페이지를 우선 로드한 뒤 이후 페이지를 차례로 가져오는 방식입니다. 24 | - 프로세스가 같은 페이지를 사용한다면 이를 함께 사용해 메모리를 절약할 수도 있고 이 페이지에 대한 테이블 (PTBR)이 필요하게 됩니다. 25 | - 이로 인해 시간, 공간적 오버헤드가 나오게 되는데 시간적 오버헤드는 자주 사용하는 페이지 테이블을 저장하는 버퍼(TLB)를 둬서 해결을 할 수 있습니다. 26 | - 압축 27 | - 비용이 많이 드는 작업입니다 28 | - 삭제 공간들을 회수해 메모리를 정리합니다. 29 | - 통합 30 | - 압축과는 다르게 인접한 것들간의 메모리를 통합하는 작업입니다. 31 | 32 | 33 | 34 | ### 내부 단편화 해결 35 | 36 | - 세그멘테이션 37 | - 페이징은 일정 크기로 나누는 것이고 세그멘테이션은 **논리 단위**를 의미합니다. 38 | - 이 논리 단위는 일정하지 않습니다. 39 | - 논리 주소와 실제 주소를 매핑하기 위한 테이블이 하나 필요하게 됩니다. 40 | - 세그멘테이션은 외부 단편화가 발생할 우려가 있고 단편화의 크기가 제멋대로라 페이징을 사용하게 됩니다. 41 | 42 | 43 | 44 | ### 둘 다 해결하는 방안 45 | 46 | - 메모리 풀 47 | - 필요한 메모리를 직접 지정해 미리 할당받은 뒤 사용한 뒤 반납하는 기법입니다. 48 | - 이런 풀링 없이 할당, 비할당을 계속하게 되면 단편화를 만들게 되지만 필요할 때마다 할당받은 메모리 공간을 가져다 쓰고 반납하기에 외부 단편화가 생기지 않게 됩니다. 49 | - 또한 "필요한"만큼이라고 했기에 내부 단편화도 없게 됩니다. 50 | - 오브젝트 풀링과 비슷한 느낌이며 할당, 해제가 빈번한 경우 유용하게 사용할 수 있습니다. -------------------------------------------------------------------------------- /OS/뮤텍스(Mutex)와 세마포어(Semaphore).md: -------------------------------------------------------------------------------- 1 | # 뮤텍스(Mutex)와 세마포어(Semaphore) 2 | 3 | > Critical Section(임계 구역) : 공유된 자원 부분 4 | 5 | 둘 다 이 임계 구역과 관련해 여러 스레드, 프로세스들이 한번에 접근하는것을 막는 방식입니다. 가장 큰 차이라고 하면 **뮤텍스 객체는 한개의 스레드/프로세스만이 가질 수 있고 세마포어의 경우 카운터 변수를 공유하면서 관리**한다는 것입니다. 6 | 7 | - Mutex 8 | - 뮤텍스 객체에 한 스레드가 접근 9 | - 뮤텍스 객체는 Lock 10 | - Lock된 객체는 다른 스레드가 접근 불가능 11 | - 스레드가 사용을 다 하면 뮤텍스 객체를 Unlock해서 타 스레드가 사용할 수 있게 함 12 | - Semaphore 13 | - 카운터 변수를 두고 있음 14 | - 스레드가 접근하면 이 카운터 변수를 -1 15 | - 만일 카운터 변수가 0이 되면 다른 스레드는 접근 불가능 (Lock) 16 | - 스레드가 사용을 다 하면 카운터 변수를 다시 1 올려줌 17 | 18 | 여기서 뮤텍스는 사실상 Binary Semaphore라고 볼 수 있습니다. -------------------------------------------------------------------------------- /OS/프로세스와 스레드.md: -------------------------------------------------------------------------------- 1 | # 프로세스와 스레드의 차이 2 | 3 | 4 | 5 | > 프로세스는 OS 에게서 받은 **작업의 단위**이며 스레드는 할당받은 자원을 사용하는 **실행 단위**입니다. 6 | 7 | 프로세스는 코드, 데이터, 힙, 스택 자원을 각자 할당받으며 다른 프로세스와 아무 관계가 없습니다. 즉, 다른 프로세스가 종료된다 하더라고 공유하는 부분의 손상이 있는게 아니라면 아무 영향을 주지 않습니다. 8 | 9 | 스레드의 경우 프로세스 안에서 실행되는 단위로 스택만을 따로 가지며 코드, 데이터, 힙은 다른 스레드들간 공유하고 있습니다. 10 | 11 | 12 | 13 | ## 멀티 프로세스와 멀티 스레드 14 | 15 | 프로세스는 무겁고 스레드는 상대적으로 가볍습니다. 때문에 멀티 스레드를 더 자주 사용하게 됩니다. 16 | 17 | - 자원 생성에 있어서 새 스택만을 주므로 이에 관한 시스템 콜이 줄어듭니다. 18 | - Context Switching을 할 때 스레드는 스택만 있어 상대적으로 빠른 전환 가능 19 | 20 | 21 | 22 | 다만 이 경우에는 여러 동기화 문제가 있으므로 이에 대해 관리를 잘 해줘야 하며 이와 관련한 질문들이 많이 나오게 됩니다. -------------------------------------------------------------------------------- /Personality Interview/게임 클라이언트 인성,경험 질문.MD: -------------------------------------------------------------------------------- 1 | ## 항상 나오는 것 2 | 3 | - 자기소개 4 | - 끝나고 질문할 것 있는지 5 | 6 | ## 개발과 관련이 있는, 하지만 기술 질문은 아닌 것들 7 | 8 | - 본인의 프로젝트에서 어떤 역할을 하였는가 9 | - 게임업계의 프로그래머가 되고 싶은 이유는 있는가 10 | - 재미있게 한 게임은 있는가? 11 | - 있다면 어떤 부분이 재미있었고 개발한다면 어떤 방식의 접근을 할 것인가? 12 | - 개발에서 원하는 프로젝트가 아닌 작업을 한다면 어떨 것 같은가 13 | - 처우가 부족해도 원하는 게임 vs 처우는 좋은데 원하지 않는 게임 14 | - 입사 후 어떤 일을 하고 싶은가 15 | - 팀장으로, 팀에서 리드 개발자로, 개발자로 활동하면서 소통에 오류가 있던 적이 있었나 16 | - 최근에 공부한 것, 학교 강의 중에서 어떤 것이 가장 기억에 남는가 17 | - 클라이언트 개발자로서 어떤 게임을 만들고 싶다 하는게 있는가 18 | - 클라이언트 개발자에게 중요한건 기술력일까 최적화일까 19 | - 1년, 3년 뒤, 10년 뒤에는 어떤 개발자가 되고 싶은가 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 | - 일정이 중요한가 vs 퀄리티가 중요한가 45 | - 평소 취미가 있는가 46 | - 스트레스 해소 노하우가 있는가 47 | - 회사 업무가 지루하다고 느껴지면 어떻게 할 것인가 48 | - 지인들이 생각하는 본인들의 장단점 49 | - 본인의 장점은 50 | - 본인의 단점은 51 | - 이런 단점의 극복 사례가 있는가 52 | - 이런 사람과 함께 일하면 퍼포먼스가 떨어진다! 어떤 유형인가 53 | - 팀 프로젝트를 하면서 정말 마음에 들지 않는 사람이다! 어떻게 할 것인가 54 | - 다른 사람에게 안좋은 이야기를 할 때는 어떻게 하는가 55 | - 본인이 안좋은 피드백을 받았을때 어떠한 자세를 취하는가 56 | - 학업이나 프로젝트에 있어서 어떠한 피드백이 본인에게 도움이 된다고 생각하는가 57 | - 이 회사에 합격하면 하고 싶은 일 58 | - 지원한 회사의 게임을 해보신적이 있는가? 59 | - 있다면 개선해야 할 부분, 흥미로운 부분은 어떤 것이었나 60 | - 우리 회사 인재상에 대해서 아는가? 61 | - 그러면 어떤 인재상과 제일 잘 맞는다고 생각하는가 62 | - 인재상에 부합하는 경험에 대해서 제시해 줄 수 있는가 63 | - 존경하는 사람, 개발자가 있는가 64 | - 팀 게임에서 어떠한 성향을 가지고 있는가? 평소 게임 하는 스타일에 대한 설명 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # For Game Developer 2 | 3 | ## 개요 4 | 5 | > 이 리포지토리를 만든 사람이 개요를 참 좋아합니다. 6 | 7 | [그냥 주인장의 글](https://husk321.tistory.com/) 8 | 9 | 게임 개발자가 되기로 결심 한 후 깨달은건 **이 분야에서 지식 공유가 많지 않다**라는 것입니다. 타 개발 분야에 비해서 정보도 적고 로드맵을 구하기가 힘들어 항상 방향을 잡는게 힘들었습니다. 10 | 11 | 다른 분들은, 어떤 경우에라도 이 리포지토리를 본 분들은 조금이라도 도움을 받으셨으면 하는 마음에 이 Org를 만들게 되었습니다. 혹시나 도움을 잘 받았다면 Star 남겨주시거나 뒤이어 게임 업계에 뛰어드는 개발자를 위해 기여해주신다면 감사하겠습니다. 또한 잘못된 오개념들을 잡아주신다면 또 한번 감사드리겠습니다.🙇‍♂️🙇‍♂️ 12 | 13 | 추가적으로 공부하다 지쳤을 때 볼만한 글을은 아래 있습니다. 탈락 후기, 합격 후기 등등이 올라올 예정이니 심심할 때 보시면 좋습니다. (본인 글을 올리고 싶으신 분들은 아래 "기여"를 참고해 주세요) 14 | 15 | [심심풀이 글 목록](#심심풀이) 16 | 17 | ## Contributors 18 | 19 | ### 🙇‍♂️ Created By 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | ## License 28 | 29 | 해당 리포지토리는 [🍻BEERWARE](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/License) 라이센스를 따릅니다. 30 | 31 | 특별한건 없고 이 리포지토리가 마음에 드셨고 유용했다면 혹시나 만날때를 위해 맥주🍻 한잔 킾 해달라는 뜻입니다. 32 | 33 | ## 기여 or 제보 34 | 35 | > 👍 이 리포지토리에 기여하고 싶으신 분들은 Pull Request를 통해 기여해주시면 됩니다. 다른건 없고 커밋 앞에 `docs : `를 붙여주시면 감사하겠습니다. 36 | 37 | > ⚒ 혹여나 잘못된 부분을 발견하신 분들은 [Issue](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/issues)를 활용해 제보해주시면 됩니다! 38 | 39 |
40 | 현재 받고있는 제보 List 41 | 42 | ### C++ 43 | 44 | - [C 에서는 Name Mangling이 일어나는가?](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/Name%20Mangling%20(Decoration).md) 45 | 46 | ### C# 47 | 48 | - [C#과 C++의 속도 관련한 이야기에 대한 제보](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/C%23%20vs%20C%2B%2B.md) 49 | 50 | --- 51 | 52 |
53 | 54 | 다만 대부분의 회사들은 **면접의 내용을 공개하지 않는걸 원칙**으로 합니다. 때문에 이런 규정을 깨고 기여는 하지 말았으면 합니다. 이곳은 **면접 대비 예상 질문을 뽑는 곳**임을 명심해주세요. 55 | 56 | 추가적으로 본인의 **취업 후기, 회고, 추천하는 로드맵**등의 글이 잘 쓰였다면 ISSUE에 작성해주세요. 해당 리포지토리 관리자가 자체 검토 후 아래 [심심풀이](#심심풀이) 리스트에 올려보도록 하겠습니다. 57 | 58 | ## 인성 면접 or 개발이라 하기에는 가벼운 질문들 59 | 60 | > [면접 질문들 Link](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Personality%20Interview/%EA%B2%8C%EC%9E%84%20%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%20%EC%9D%B8%EC%84%B1%2C%EA%B2%BD%ED%97%98%20%EC%A7%88%EB%AC%B8.MD) 61 | 62 | 해당 항목은 게임 회사에서 질문이 나올 수 있는 여러가지 가벼운 개발 상황 질문, 인성 질문들을 모아둔 곳입니다. 질문들에 대한 공식적인 답이 없을 뿐더러 회사마다 같은 답변에 대해서 다른 포지션을 취할 수 있으니 **'🤦‍♂️🤦‍♀️*아 이런 질문들이 있구나'*** 정도로 생각하시고 본인만의 답을 준비해 가는게 좋습니다. 면접에서 바로 생각하는 것 대신 미리 얼추 생각하고 들어가는 것이죠. 63 | 64 | ## C++ 65 | 66 | - [struct와 class의 차이](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/struct%2C%20class.md) 67 | - [포인터와 배열의 차이](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%99%80%20%EB%B0%B0%EC%97%B4%EC%9D%98%20%EC%B0%A8%EC%9D%B4.md) 68 | - [malloc/free vs new/delete](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/mallocfree%20vs%20newdelete.md) 69 | - [오버로딩/오버라이딩](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%20%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9.md) 70 | - [const와 관련한 이야기](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/const.md) 71 | - [static과 관련한 이야기](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/static.md) 72 | - [가상 소멸자를 사용하는 이유](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%EA%B0%80%EC%83%81%20%EC%86%8C%EB%A9%B8%EC%9E%90.md) 73 | - [상등성과 동등성의 차이](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%EC%83%81%EB%93%B1%EC%84%B1%EA%B3%BC%20%EB%8F%99%EB%93%B1%EC%84%B1.md) 74 | - [vector와 관련한 이야기](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/vector%EC%99%80%20%EA%B4%80%EB%A0%A8%ED%95%9C%20%EC%9D%B4%EC%95%BC%EA%B8%B0%EB%93%A4.md) 75 | - [C++에서 map과 unordered_map의 차이](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/map%20vs%20unordered_map.md) 76 | - [`` 헤더의 sort와 list.sort](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/algorithm%20sort%EB%8A%94%20%EC%96%B4%EB%96%A4%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%B8%EA%B0%80.md) 77 | - [C++ 캐스팅](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/cast.md) 78 | - [template의 장단점](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/template.md) 79 | - [typedef vs using](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/typedef%20vs%20using(%EB%B3%84%EC%B9%AD%20%EC%84%A0%EC%96%B8).md) 80 | - [얕은복사/깊은복사](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%EC%96%95%EC%9D%80%EB%B3%B5%EC%82%AC%EC%99%80%20%EA%B9%8A%EC%9D%80%EB%B3%B5%EC%82%AC.md) 81 | - [L-value, R-value](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/L-value%2C%20R-value.md) 82 | - [Move Semantics - 이동 의미론](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/Move%20Semantics%20-%20%EC%9D%B4%EB%8F%99%20%EC%9D%98%EB%AF%B8%EB%A1%A0.md) 83 | - [스마트 포인터](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/%EC%8A%A4%EB%A7%88%ED%8A%B8%20%ED%8F%AC%EC%9D%B8%ED%84%B0.md) 84 | - [Name Mangling](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/Name%20Mangling%20(Decoration).md) 85 | 86 | ## C# & Unity 87 | 88 | 클라이언트 개발자에게 Unity + C# 조합으로 질문이 많이 들어오게 되니 이 둘은 같은 목차에 넣게 되었습니다. 89 | 90 | - [유니티 생명주기](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/Unity%EC%9D%98%20%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0.md) 91 | - [Awake vs Start / Update vs FixedUpdate vs LateUpdate](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/Awake_Start_Update_FixedUpdate_LateUpdate.md) 92 | - [박싱, 언박싱](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/%EB%B0%95%EC%8B%B1%2C%20%EC%96%B8%EB%B0%95%EC%8B%B1.md) 93 | - [직렬화 역직렬화](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/%EC%A7%81%EB%A0%AC%ED%99%94%20-%20Serialization%20%20%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94%20-%20Deserialization.md) 94 | - [const vs readonly](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/const%20readonly.md) 95 | - [C#의 String](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/C%23%EC%9D%98%20string.md) 96 | - [GC - Garbage Collector](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/Unity%20%26%20C%23%EC%9D%98%20GC.md) 97 | - [delegate와 event](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/delegate%EC%99%80%20event.md) 98 | - [this](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/this.md) 99 | - [List, Dictionary 외 등 자료구조의 내부](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/List_Dictionary.md) 100 | - [C#은 C++보다 느릴까](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/C%23%20vs%20C%2B%2B.md) 101 | 102 | ## Unreal 103 | 104 | - [Isvalid](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unreal/IsValid.md) 105 | - [언리얼 문자열 클래스들](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unreal/Unreal%20String%20Classes.md) 106 | 107 | ## OS 108 | 109 | - [리틀 앤디언과 빅 앤디언](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/%EB%A6%AC%ED%8B%80%20%EC%95%A4%EB%94%94%EC%96%B8%2C%20%EB%B9%85%20%EC%95%A4%EB%94%94%EC%96%B8.md) 110 | - [프로세스와 스레드](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80%20%EC%8A%A4%EB%A0%88%EB%93%9C.md) 111 | - [메모리 단편화 - Memory Fragmentation](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/%EB%A9%94%EB%AA%A8%EB%A6%AC%20%EB%8B%A8%ED%8E%B8%ED%99%94%20-%20Memory%20Fragmentation.md) 112 | - [뮤텍스(Mutex)와 세마포어(Semaphore)](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/%EB%AE%A4%ED%85%8D%EC%8A%A4(Mutex)%EC%99%80%20%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4(Semaphore).md) 113 | - [CPU 스케쥴러 알고리즘 종류](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/CPU%20%EC%8A%A4%EC%BC%80%EC%A5%B4%EB%9F%AC%EC%9D%98%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A2%85%EB%A5%98.md) 114 | - [가상 메모리](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/%EA%B0%80%EC%83%81%20%EB%A9%94%EB%AA%A8%EB%A6%AC%20-%20Virtual%20Memory.md) 115 | - [데드락 - DeadLock](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OS/DeadLock%20(%EB%8D%B0%EB%93%9C%EB%9D%BD%2C%20%EA%B5%90%EC%B0%A9%20%EC%83%81%ED%83%9C%2C%20%EC%9D%B4%ED%95%98%20%EB%8D%B0%EB%93%9C%EB%9D%BD).md) 116 | 117 | ## OOP 118 | 119 | - [객체지향 5원칙](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/OOP/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A55%EC%9B%90%EC%B9%99.md) 120 | 121 | ## DB 122 | 123 | - [Key](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DB/Key.md) 124 | - [정규화](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DB/%EC%A0%95%EA%B7%9C%ED%98%95.md) 125 | 126 | ## 디자인 패턴 127 | 128 | - [싱글톤 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/SingletonPattern.md) 129 | - [널 오브젝트 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/NullObjectPattern.md) 130 | - [스트래터지 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/StrategyPattern.md) 131 | - [프록시 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/ProxyPattern.md) 132 | - [퍼사드 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/FacadePattern.md) 133 | - [스테이트 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/StatePattern.md) 134 | - [어댑터 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/AdapterPattern.md) 135 | - [옵저버 패턴](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/DesignPattern/ObserverPattern.md) 136 | 137 | --- 138 | 139 | ### 심심풀이 140 | 141 | - [주인장의 2022 EA Winter Intern 탈락 후기](https://husk321.tistory.com/401) 142 | 143 | - [주인장의 UNSEEN-언리얼 교육 프로그램 지원 후기](https://husk321.tistory.com/416) 144 | - [위 UNSEEN 언리얼 교육 후기](https://husk321.tistory.com/444) 145 | -------------------------------------------------------------------------------- /Unity_C#/Awake_Start_Update_FixedUpdate_LateUpdate.md: -------------------------------------------------------------------------------- 1 | 2 | > 이 질문을 보기 전 사전 지식으로 [유니티 생명주기](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/Unity_C%23/Unity%EC%9D%98%20%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0.md)문서를 보는걸 추천드립니다. 3 | 4 | # Awake vs Start 5 | 6 | 둘 다 클래스의 초기화에 사용되는 이벤트 함수로 호출 시기에 따른 차이가 있습니다. 7 | 8 | - Awake 9 | - 스크립트와 연결된 GameObject가 인스턴스화 되거나 스크립트가 처음 로드될 떄 불림 10 | - 해당 오브젝트가 Enable 상태가 아니라고 해도 위 조건에 따라 로드되면 호출됨 11 | - 다른 오브젝트에 대한 참조를 생성할 때 주로 사용하게 됨 12 | - 단 Awake 호출은 무작위 13 | - 무작위성으로 인해 다른 스크립트의 참조를 통해 접근을 하면 `NullReferenceException`이 발생하게 됨 14 | - Start 15 | - 해당 스크립트 컴포넌트가 활성화 되는 순간 불리게 됨 16 | - 호출 시기는 Awake 보다는 느리게 첫 Update보다는 빠르게 불린다 17 | - Start에서는 참조를 통해 접근하는 작업이 가능함 18 | 19 | 20 | ## OnEnable vs Start 21 | 22 | 둘 다 '컴포넌트가 활성화 될 때' 불린다는 공통점이 있어 묶이게 되지만 Start는 한번, OnEnable은 활성화 될 때 마다 불리게 된다는 차이점이 있습니다. 때문에 초기화 작업에 OnEnable을 활용하면 안됩니다. OnEnable은 주로 오브젝트 풀링에 사용하게 되는 함수라고 볼 수 있습니다. 23 | 24 | 25 | # Update vs FixedUpdate vs LateUpdate 26 | 27 | - Update : 프레임 단위로 호출됨 28 | - LateUpdate : Update 호출 뒤 불리게 됨 29 | - FixedUpdate : 고정 단위로 불리게 되는 함수 30 | 31 | 여기는 FixedUpdate의 '고정 단위'를 아는게 중요합니다. 이 고정 단위는 물리 엔진에 의해 결정이 되므로 컴퓨터 성능에 따라 프레임이 다르게 나와 호출 간격이 일정하지 않은 Update와는 달리 일정하게 불리게 됩니다. 이런 이유로 인해서 Rigidbody를 조작할 때는 FixedUpdate를 사용하게 됩니다. -------------------------------------------------------------------------------- /Unity_C#/C# vs C++.md: -------------------------------------------------------------------------------- 1 | # C# vs C++ 2 | 3 | 4 | 5 | 주요 차이점으로 나오는게 C#은 GC가 달려 있어서 C++보다 느리다! 라는 이야기들입니다. 그런데 C++도 GC와 동일하게 delete를 한다면 사실상 비슷한 작업을 하기에 완벽한 답이 될 수는 없습니다. 때문에 이번에 C#과 C++의 `속도`를 중점으로 해서 비교하는 문제에 대한 답을 어느정도 적어보려고 합니다. 6 | 7 | 물론 필자 또한 완벽한 답을 아직 이끌어내지 못했기에 아래 글들과 참고 자료들, 본인의 검색 결과 등을 바탕으로 면접때 대답하는걸 추천드리겠습니다. 8 | 9 | 10 | 11 | ## GC 12 | 13 | 둘의 큰 차이를 고른다면 가장 이런게 나오지 않을까 합니다. 14 | 15 | 일단 C#의 GC는 `Mark and Sweep`알고리즘에 기반을 두고 있으므로 힙에 할당된 객체에 대한 포인터 추적을 실행하게 됩니다. 이로 인해서 C++의 생성-소멸 주기보다는 오버헤드가 걸리는게 맞습니다. 그리고 수많은 객체들을 생성한 후 나중에 GC를 돌리게 되면 더 많은 시간을 사용하게 되므로 속도가 더 느려지게 됩니다. 16 | 17 | C#이 마냥 관망하는건 아니라서 세대 기반 알고리즘을 도입해 '살아 있을 가능성이 있는 객체'를 뒤로 물러나게 해 GC 시간을 줄이는 등의 노력을 하고 있습니다. 때문에 GC 작업으로 인한 차이를 재는게 무의미하다 라고 하는 의견들이 더럿 있었습니다. 18 | 19 | 20 | 21 | ## 가상 머신 (VM - Virtual Machine) 22 | 23 | VM에 대해서도 마냥 '이거 때문에 느리다!'라고 이야기 할 수 없습니다. 24 | 25 | 'VM을 사용하면 느리다'라는 말이 나오는 주된 이유는 초기 구동시에 JIT 컴파일러를 위해 한번 대기하는 과정이 있어서 라고 합니다. 다만 이 경우 한번 실행이 되면 이후에는 여러번 사용할 수 있기에 이에 대한 오버헤드를 잘 살펴봐야 합니다. (대부분의 언어 벤치마크들이 욕먹는 이유중 하나) 26 | 27 | 일단 C++로 작성된 프로그램은 대부분 32비트 코드로 컴파일이 되며 64비트 프로세서에서도 32비트로 돌아가게 됩니다. JIT를 사용하는 C#의 경우 타겟 플랫폼에 대한 이해도를 가질 수 있어서 64비트에 맞춰 컴파일을 할 것입니다. 때문에 이런 부분에 있어서 장점을 가질 수도 있습니다. (C++로 이 작업을 하려면 복잡하고 비슷한 결과가 나올 것으로 예측됨) 28 | 29 | 30 | 31 | ## C++의 TMP, C#의 리플렉션 32 | 33 | C++의 TMP는 정적인 프로그램으로 컴파일 시간에 계산을 할 수 있다는 장점이 있습니다. 다만 이 경우 런타임에 수행될 수 없다는 단점이 있습니다. 예시로 TMP로 팩토리얼을 O(1)로 계산할 수 있지만 이는 컴파일 타임, 사용자 입력에 따른 유동성을 고려하지 않은 것입니다. 34 | 35 | C#의 경우에는 런타임에 리플렉션을 통해 수행을 하게 됩니다. 때문에 '런타임'이라는 특성만 보고 느리다고 할 수 있는데 이에 대한건 확실히 trade-off가 있는 것입니다. 36 | 37 | 38 | 39 | ## 필자의 결론 40 | 41 | 이런 이야기들을 보면 마냥 C#을 느리다고는 할 수 없지만 대부분의 경우에서 C++이 속도적으로 우세하다는 이야기를 들을 수 있습니다. 하지만 이는 '대부분'으로 100%라는 뜻은 아니죠. 때문에 단순하게 나오는 벤치마크를 믿고 다니기 보다는 본인만의 환경에서, 본인 프로그램에 대한 코드를 작성해 봤을 때 성능 비교가 중요하다는 생각이 듭니다. 42 | 43 | 'C#이 사실 더 빠르다!', 'C++이 더 빠르다!'와 같은 명확한 답변을 원하셨을 수 있는데 필자의 역량과 경험이 뛰어나지 않아 이 부분에 대한 질의를 완성할 수 없음에 아쉬움을 느낍니다. 44 | 45 | 혹시나 이에 대해 아시는 정보들을 기여하고 싶으시다면 해당 리포지토리의 README를 참고해 기여해주시면 감사하겠습니다. 46 | 47 | 48 | 49 | ### 주요 참고 자료 50 | 51 | [StackOverflow - Is C# really slower than say C++](https://stackoverflow.com/questions/5326269/is-c-sharp-really-slower-than-say-c) -------------------------------------------------------------------------------- /Unity_C#/C#의 string.md: -------------------------------------------------------------------------------- 1 | # C#의 string 2 | 3 | 4 | 5 | C#에서의 string은 immutable(불변) 속성을 가지고 있습니다. string이 이렇게 불변속성이 된 이유는 멀티스레드 환경을 고려해 여러 스레드들이 엑세스 할 때 이들에 대한 동기화 처리를 하는 것보다 변경이 안되게 **읽기 전용**으로 만드는게 값이 더 싸다고 생각한 것입니다. 6 | 7 | 때문에 string에 대한 조작(+=, -= 등)을 하게 되면 이전의 객체에서 복사 후 연산을 한 뒤 이를 대입해주므로 이전의 객체는 가비지가 되어 이후 GC의 처리를 받게 됩니다. 때문에 수정이 많이 일어나는 문자열로 예상이 된다면 `StringBuilder`등의 클래스를 사용하는게 좋습니다. 8 | 9 | 10 | 11 | ## StringBuilder는 어떻게 string 보다 수정에 용이할까? 12 | 13 | StringBuilder는 기본적으로 16문자를 담을 수 있는 자리를 잡습니다. 이렇게 할당 된 크기 내에서는 어떠한 수정을 해도 가비지가 생성되지 않습니다. 14 | 15 | 만일 미리 할당한 버퍼가 다 찬 상태에서 append를 하게 되면 **새 버퍼를 할당한 뒤 버퍼간 링크를 구성**한다고 합니다. 16 | 17 | > 다만 .Net 4.0 이전은 C++ vector 처럼 이전의 버퍼를 GC로 넘기고 새 버퍼를 할당하는 방식으로 했습니다. -------------------------------------------------------------------------------- /Unity_C#/List_Dictionary.md: -------------------------------------------------------------------------------- 1 | ## List와 Dictionary 2 | 3 | > C++에 대한 지식이 있다면 List는 vector, Dictionary는 unordered_map으로 생각하면 편합니다. 4 | 5 | 보통 면접에서는 List, Dictionary같은 C#의 컨테이너 클래스들을 사용해 봤는지 물어보게 됩니다. 그런 다음 내부 자료구조, 연산들에 대한 시간복잡도 이야기들이 오갈 수 있으니 알아두는게 좋습니다. 6 | 7 | ### 내부 자료구조 8 | 9 | | 컨테이너 | 자료구조 | 10 | | --------------------- | -------------- | 11 | | `List<>` | 배열 | 12 | | `SortedSet<>` | 레드-블랙 트리 | 13 | | `HashSet<>` | 해시 테이블 | 14 | | `Dictionary<,>` | 해시 테이블 | 15 | | `SortedList<,>` | 배열 | 16 | | `SortedDictionary<,>` | 레드-블랙 트리 | 17 | 18 | 19 | 20 | ### List는 C++의 vector와 유사하다 21 | 22 | `List`는 C++의 `vector`와 유사하게 동작하며 메모리에는 배열처럼 올라가게 됩니다. 또한 원소 삽입이 있을 때 `List`의 용량을 초과하게 되면 새 공간을 할당해 기존 원소들을 복사해 가기에 최대 O(N) 시간 복잡도를 가지게 될 수도 있습니다. 23 | 24 | (Remove의 경우 따로 용량 변화가 없습니다) 25 | 26 | 27 | 28 | ### 그럼 SortedSet은 set, HashSet은 unordered_set 이다 29 | 30 | C++과 비교를 하면 제목과 같은 이야기가 오게 됩니다. 31 | 32 | 내부적으로 레드-블랙 트리를 사용하는 자료구조들의 경우 정렬된 완전 이진트리 이므로 삽입, 삭제에 있어서 O(logN) 시간이 소요되며 해시를 사용하는 자료구조들은 대부분 O(1)이지만 최악의 경우 O(N)이 될 수 있음을 알아야 합니다. 33 | 34 | 자세한 내용은 [C++에서 map과 unordered_map의 차이](https://github.com/Romanticism-GameDeveloper/GameDeveloper-Client-Interview/blob/main/C%2B%2B/map%20vs%20unordered_map.md)를 참고해 주세요. 35 | 36 | 37 | 38 | ### Dictionary vs SortedDictionary 39 | 40 | 대부분의 경우에서 성능은 `Dictionary`가 더 뛰어남을 알 수 있습니다. 오래 전이지만 [2008년의 자료](https://social.msdn.microsoft.com/Forums/vstudio/en-US/7513bbe6-5bd3-4309-8cca-7056043fb95a/sorteddictionary-vs-dictionary?forum=csharpgeneral)를 보면 50000만개 삽입에는 `Dictionary`가 3배 빠르고, 검색에는 아주 근소한 차이로 `SortedDictionary`가 빠름을 알 수 있었습니다. 41 | 42 | 때문에 항시 정렬된 상태로 데이터를 저장하는 것 외에는 `Dictionary` 사용이 더 좋습니다. -------------------------------------------------------------------------------- /Unity_C#/Unity & C#의 GC.md: -------------------------------------------------------------------------------- 1 | # Unity & C#의 GC 2 | 3 | C++과의 대표적인 차이가 GC의 유무 입니다. 4 | 5 | 6 | 7 | 일단 C#, 즉 .Net 의 GC는 `Mark and Sweep` 알고리즘을 사용하고 있습니다. 이를 간단하게 설명하겠습니다. 8 | 9 | - 전역 변수, 현재 함수의 로컬 변수 등을 Root로 잡게 됩니다. 10 | - 이 Root를 기반으로 점점 참조를 타고 다니면서 방문한 것들을 Mark 해줍니다. 11 | - 이러한 Mark 작업이 끝나게 된다면 이후 Sweep 단계로 진입합니다. 12 | - Sweep 단계에서는 Mark 되지 않은 것들을 가비지로 판단해 처리하게 됩니다. 13 | 14 | 이런 작업을 거쳐 GC가 동작을 하게 됩니다. 15 | 16 | 17 | 18 | ## .Net과 Unity의 GC 19 | 20 | 이 둘의 차이에 대한 질문들도 자주 나오게 됩니다. 21 | 22 | 일단 내부적으로 GC의 알고리즘은 `Mark and Sweep`를 기반으로 하게 되는데 그 이후의 과정이 다르게 됩니다. 23 | 24 | .Net에서는 0~2세대까지 총 3개의 세대를 통해서 관리를 하게 됩니다. 25 | 26 | 유니티에서는 [`Boehm-Demers-Weiser`](https://www.hboehm.info/gc/gcdescr.html) 라는 알고리즘을 통해 GC 작업을 하게 됩니다. `Mark and Sweep`인것은 같으나 세대 구분이 없고 메모리 정렬도 없습니다. 때문에 19 버전 이상에서 제공하게 되는 점진적 GC 작업을 활용하거나 오브젝트 풀링 등의 기법을 활용해서 최대한 최적화를 해줘야 할 필요가 있습니다. 27 | 28 | 29 | 30 | ## 상호 참조 해결법 31 | 32 | C#에서 상호참조중인 객체 해제에 대해서는 위 `Mark and Sweep` 알고리즘을 설명하면 됩니다. 33 | 34 | 만일 두 객체가 서로 참조중이라 하더라도 외부에서 참조가 없어 Mark 되지 않는다면 Sweep 단계에서 해제되게 됩니다. -------------------------------------------------------------------------------- /Unity_C#/Unity의 생명주기.md: -------------------------------------------------------------------------------- 1 | # Unity의 생명주기 2 | 3 | 4 | 5 |
6 | 너무 길어서 분리하게 된 유니티 생명주기 이미지 7 | 8 | ![Unity 생명주기](https://docs.unity3d.com/kr/2019.4/uploads/Main/monobehaviour_flowchart.svg) 9 | 이미지 출처 : 유니티 공식 docs - https://docs.unity3d.com/kr/2019.4/Manual/ExecutionOrder.html 10 | --- 11 |
12 | 13 | 14 | 15 | 유니티 생명 주기와 관련한 질문들이 나올 수 있으니 각 Update들의 차이, 불리는 순서 같은건 알아가는게 좋습니다. -------------------------------------------------------------------------------- /Unity_C#/const readonly.md: -------------------------------------------------------------------------------- 1 | # const vs readonly 2 | 3 | C++과 다르게 C#에서는 readonly 가 있어 수정이 안되는 읽기 전용 키워드를 제공하고 있습니다. 이 둘의 차이를 간단하게 보겠습니다. 4 | 5 | - const 6 | - 컴파일 타임 상수 (컴파일 시 변수가 값으로 대체) 7 | - 스택에 위치하게 된다 8 | - 선언과 동시에 값을 할당 9 | - 내장 자료형에만 사용 가능 10 | - 때문에 사용자 정의 클래스로는 불가능 11 | - readonly 12 | - 런타임 상수 (런타임에 상수에 대한 참조) 13 | - 힙에 위치하게 된다 14 | - 생성자에서 초기화 가능 (그 외 변경 불가능) 15 | - 어떤 타입과도 사용 가능 16 | 17 | 18 | ## const 보다는 readonly가 좋다 19 | 20 | > 한빛미디어 "Effective C# 3판" 아이템 2의 내용입니다. 21 | 22 | 둘 중 가장 큰 차이는 readonly는 상수에 대한 참조 코드를 생성한다는 점입니다. 때문에 const의 값을 변경하게 된다면 이를 사용하는 곳은 전부 재컴파일을 해야 합니다. 만일 하지 않으면 이전의 const 값으로 되어 있어 문제가 될 수 있습니다. 23 | 다만 readonly의 경우에는 일부만 리빌드 해도 이를 사용하는 다른 코드들은 참조를 가지고 있으므로 리빌드 없이 올바르게 사용이 가능합니다. 24 | 25 | 그 외 const는 스택에 있어 빠르다는 장점을 가지고 있지만 그 외의 유연성이 떨어지기에 아래 경우들을 제외하고 가급적 readonly를 사용하는게 좋습니다. 26 | 27 | - 특성의 매개변수 28 | - switch/case 문의 레이블 29 | - enum 정의 30 | 31 | -------------------------------------------------------------------------------- /Unity_C#/delegate와 event.md: -------------------------------------------------------------------------------- 1 | # delegate & event 2 | 3 | > delegate : 대표, 위임하다 4 | 5 | ## delegate (델리게이트) 6 | 7 | C# 에서 델리게이트는 함수를 타입화 한 것입니다. C++ 에서 함수 포인터와 비슷한 개념이라고 생각하면 됩니다. 8 | 파라미터와 리턴 타입을 통해 정의하게 되며 이후 리턴, 파라미터 타입이 같은 메소드들과 호환되어 이 메소드들에 대한 참조를 가질 수 있게 됩니다. 9 | 10 | ```cs 11 | public delegate void VoidAndIntEx(int i); 12 | 13 | public class ExampleClass 14 | { 15 | public void DoSomething(VoidAndIntEx exFunc) 16 | { 17 | // 인자로 받은 함수를 호출한다 18 | exFunc(1); 19 | } 20 | } 21 | ``` 22 | 23 | C#에서 이런 델리게이트를 활용해 메소드를 담아두는 역할을 하거나 함수 인자로 넘겨 콜백 패턴을 구현하는 등 다양한 곳에 사용하게 됩니다. 24 | 25 | 26 | ## event 27 | 28 | 이벤트는 결국 델리게이트와 비슷한 일을 하게 되지만 한가지 큰 차이점이 **이벤트를 호출 할 수 있는건 해당 이벤트를 가진 클래스**만 가능하다는 것입니다. 29 | 30 | ```cs 31 | class ExampleClass 32 | { 33 | // Action에 대한 설명은 아래 34 | public event Action ExampleEvent; 35 | 36 | //... 37 | if(ExampleEvent != null) 38 | { 39 | ExampleEvent(); 40 | } 41 | } 42 | ``` 43 | 44 | ## Action, Func, Predicate 45 | 46 | 이 키워드들은 자주 사용하게 되는 델리게이트를 템플릿화 한 것들입니다. 47 | 48 | - Action 49 | - 함수 파라미터가 T 이고 반환값이 void 인 경우 50 | - Func 51 | - 함수 파라미터가 T 이고 반환값이 TResult 인 경우 52 | - Predicate 53 | - 함수 파라미터가 T 이고 반환값이 bool 인 경우 54 | 55 | 56 | ## null 조건부 연산자 (?.) 57 | 58 | > null 체크 연산자 등의 말이 있지만 현재 문서에서는 [MS docs](https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-)의 표기를 따랐습니다. 59 | 60 | 델리게이트나 이벤트를 다루다 보면 null인지 체크를 해줘야 합니다. 만일 null인 델리게이트를 호출한다면 NullReferenceException이 발생하게 됩니다. 61 | 62 | ```cs 63 | if(ExampleEvent != null) 64 | { 65 | ExampleEvent(); 66 | } 67 | ``` 68 | 69 | 위 코드에서 문제점은 2가지 있습니다. 70 | - 멀티 스레드에서 호출할 경우의 문제 71 | - 그냥 타자가 많다 72 | 73 | 멀티 스레드에서 문제는 복잡하게 됩니다. 위 코드에 주석을 달아 설명을 해 보겠습니다. 74 | 75 | ```cs 76 | if(ExampleEvent != null) // 여기서는 문제 없었는데 77 | { 78 | // 여기서 다른 스레드가 구독을 취소해서 null이 됨! 79 | ExampleEvent(); // NullReferenceException! 80 | } 81 | ``` 82 | 83 | 이런 복잡한 문제는 검출이 어렵기에 아래 '복사 후 실행' 이란 방법을 통해서 예방할 수 있습니다. 84 | 85 | ```cs 86 | var CopiedEvent = ExampleEvent; 87 | 88 | if(CopiedEvent != null) 89 | { 90 | // 여기서 ExampleEvent 구독 취소 해도 문제 X 91 | CopiedEvent(); 92 | } 93 | ``` 94 | 95 | 다만 이 경우 위에 언급한 '타자가 많다' 문제는 해결하지 못합니다. 매번 복사한다는것도 좋은 방안이 아니구요. 96 | 97 | 때문에 `?.` 연산자를 활용하는 것입니다. `?.` 연산자는 `?` 왼쪽의 항이 null이 아니라면 `.` 뒷부분을 실행하겠다는 의미의 연산자 입니다. 98 | 99 | ```cs 100 | ExampleEvent?.Invoke(); 101 | ``` 102 | 103 | 함수의 경우 `Invoke`를 붙여서 호출할 수 있게 됩니다. 그리고 이 연산자의 경우 **원자적으로 수행이 되는 연산자**라서 이 연산 도중 다른 스레드가 개입할 여지가 없어 멀티 스레드 환경에서도 안전하게 돌아가게 됩니다. -------------------------------------------------------------------------------- /Unity_C#/this.md: -------------------------------------------------------------------------------- 1 | # this 2 | 3 | C#에서 this는 여러군데 사용되기에 다른 질문을 하다가 연계 질문으로 잠깐 들어올 가능성이 있습니다. 스쳐 지나가듯 물어보는? 그런 느낌이 되겠네요. 4 | 5 | 6 | ## 클래스의 현재 인스턴스 this 7 | 8 | 흔히 다른 언어에서도 지원하는 것으로 **클래스의 현재 인스턴스**를 가리키는 키워드입니다. 매개변수 이름과 클래스 필드가 이름이 같다면 this로 구분할 수 있게 됩니다. 9 | 10 | 클래스 내에서 클래스 필드를 사용할 때는 다 this가 생략된 경우라고 볼 수 있습니다. 11 | 12 | 13 | ## 생성자 this() 14 | 15 | 생성자의 이름은 클래스 이름과 동일해야 하며 void 형식이어야 합니다. 16 | 17 | ```cs 18 | class MyClass 19 | { 20 | int a; 21 | int b; 22 | 23 | public MyClass() 24 | { 25 | a = 10; 26 | } 27 | 28 | public Myclass(int b) 29 | { 30 | a = 10; 31 | this.b = b; 32 | } 33 | } 34 | ``` 35 | 36 | 다만 이 경우 너무 중복되는 코드들이 양산될 수 있어서 `this()` 생성자를 사용하는 것입니다. `this()`는 자기 자신의 생성자를 가리키며 이는 생성자에서만 활용이 가능합니다. 37 | 38 | ```cs 39 | class MyClass 40 | { 41 | int a; 42 | int b; 43 | 44 | public MyClass() 45 | { 46 | a = 10; 47 | } 48 | 49 | public Myclass(int b) : this() 50 | { 51 | this.b = b; 52 | } 53 | } 54 | ``` 55 | 56 | `this()` 키워드는 생성자를 가리키기에 인자를 줘서 인자를 받는 다른 생성자를 가리킬 수도 있습니다. 57 | 58 | 59 | ## 정적 함수 파라미터의 this 60 | 61 | ```cs 62 | public static void Shuffle(this IList list) 63 | ``` 64 | 65 | 정적 함수 파라미터에 하는 this는 `확장 메서드`를 만드는데 사용되는 키워드입니다. 이를 활용하면 멤버 함수를 호출하듯 함수를 호출할 수 있게 됩니다. 66 | 67 | ```cs 68 | List exList = new List(); 69 | //... 70 | Shuffle(exList); // 이렇게도 되고 71 | exList.Shuffle(); // 이렇게도 된다! this 덕분에! 72 | ``` 73 | 74 | 이런 식으로 클래스나 인터페이스를 확장할 수 있게 됩니다. 75 | 76 | 다만 기존 클래스의 함수와 동일한 시그니처로 정의하면 호출되지 않게 됩니다. 이 이유는 확장 메서드는 컴파일 타임에 바인딩이 되는데 컴파일러가 함수 호출을 볼 때 인스턴스 함수를 먼저 보게 되고 그 다음 확장 메서드를 보게 됩니다. 때문에 확장 메서드가 우선순위에서 밀려 호출되지 않게 되는 것입니다. -------------------------------------------------------------------------------- /Unity_C#/박싱, 언박싱.md: -------------------------------------------------------------------------------- 1 | # 박싱, 언박싱 2 | 3 | 4 | 5 | 이를 알기 위해서는 `값 타입`과 `참조 타입`에 대해서 알아야 합니다. 6 | 7 | - 값 타입 8 | - C#에서 구조체, 열거 타입 등은 값 타입입니다. 9 | - System.ValueType 로부터 항상 상속 10 | - 스레드 스택에 할당이 됩니다. 11 | - 참조 타입 12 | - C#에서는 모든 클래스는 참조 타입이 됩니다. 13 | - System.Object로부터 상속 14 | - 힙에 저장이 되며 GC가 관리하게 됩니다. 15 | - 이 힙 메모리의 주소를 가리키는 값은 스택에 저장이 됩니다. 16 | 17 | 여기서 박싱과 언박싱의 차이를 이야기 하면 18 | 19 | - 박싱 : 값 타입을 참조 타입으로 변경 20 | - 언박싱 : 참조 타입을 값 타입으로 변경 21 | 22 | 이며 이 둘의 작업은 기본 작업들에 비해 비용이 크기 때문에 가급적 사용하지 않는게 좋습니다. 다시 박싱, 언박싱 과정을 통해서 힙에 가비지가 쌓여 GC에 무리를 줄 수 있는 작업이기 때문이죠. 23 | 24 | 25 | 26 | 이를 해결하기 위해서는 가급적 제네릭을 활용해 줘야 합니다. -------------------------------------------------------------------------------- /Unity_C#/직렬화 - Serialization 역직렬화 - Deserialization.md: -------------------------------------------------------------------------------- 1 | # 직렬화 - Serialization / 역직렬화 - Deserialization 2 | 3 | 4 | 5 | ## 이 둘에 대한 정의 6 | 7 | `직렬화`는 특정 객체를 바이트 단위로 변경한 뒤 디스크에 저장하거나 네트워크로 보낼 수 있게 만들어주는 것입니다. `역직렬화`는 직렬화된 바이트 배열을 원래 객체로 변경하는 과정을 의미합니다. 8 | 9 | 10 | 11 | ## 직렬화를 왜 하는가? 12 | 13 | 역직렬화는 직렬화가 있으면 당연히 따라오는 친구라 존재 이유를 물어보지는 않는 편입니다. 14 | 15 | 직렬화의 경우에는 현재 사용하고 있는 데이터에 대해서 `영속성`을 부여하기 위함입니다. 영속성은 프로그램을 종료하더라도 사라지지 않는 특성을 의미합니다. 16 | 17 | 이런식으로 프로그램 종료 후에도 객체에 관한 정보를 남겨두고 싶을 때 직렬화를 사용하게 됩니다. 주로 플레이어의 데이터들이 이에 속하게 되는 것이죠. 18 | 19 | 20 | 21 | ## 유니티에서 직렬화가 되는 것들 22 | 23 | 다만 모든 것들이 직렬화가 되어 저장할 수 있는 상태가 되는건 아닙니다. 또한 유니티의 경우에는 다른 언어들과는 살짝 다르게 동작할 수 있으니 알아두는것 정도는 괜찮습니다. 24 | 25 | - public이거나 [SerializeField] 속성이 있어야 함 26 | 27 | - static, const, readonly가 아니어야 함 28 | 29 | - 직렬화 할 수 있는 필드 타입이 있어야 함 30 | 31 | => 직렬화 할 수 있는 필드타입은 아래와 같습니다. 32 | 33 | - [Serializable] 속성이 있는 비추상, 비일반 커스텀 클래스 34 | - [Serializable] 속성이 있는 커스텀 구조체 35 | - `UnityEngine.Object`에서 파생된 오브젝트에 대한 레퍼런스 36 | - int, double, bool 같은 기본 데이터 형식 37 | - 열거형 타입 38 | - Vector2, Vcetor3, Color 등과 같은 특정 Unity 내장 타입 39 | 40 | -------------------------------------------------------------------------------- /Unreal/IsValid.md: -------------------------------------------------------------------------------- 1 | ## IsValid, == nullptr, check 차이 2 | 3 | ### IsValid 4 | 5 | ```cpp 6 | FORCEINLINE bool IsValid(const UObject *Test) 7 | { 8 | return Test && FInternalUObjectBaseUtilityIsValidFlagsChecker::CheckObjectValidBasedOnItsFlags(Test); 9 | } 10 | ``` 11 | 12 | `IsValid`의 경우 단순 nullptr 체크 뿐 아니라 내부 플래그도 검사하는 작업을 거치게 됩니다. 13 | 14 | ```cpp 15 | struct FInternalUObjectBaseUtilityIsValidFlagsChecker 16 | { 17 | FORCEINLINE static bool CheckObjectValidBasedOnItsFlags(const UObject* Test) 18 | { 19 | // Here we don't really check if the flags match but if the end result is the same 20 | PRAGMA_DISABLE_DEPRECATION_WARNINGS 21 | checkSlow(GUObjectArray.IndexToObject(Test->InternalIndex)->HasAnyFlags(EInternalObjectFlags::PendingKill | EInternalObjectFlags::Garbage) == Test->HasAnyFlags(RF_InternalPendingKill | RF_InternalGarbage)); 22 | PRAGMA_ENABLE_DEPRECATION_WARNINGS 23 | return !Test->HasAnyFlags(RF_InternalPendingKill | RF_InternalGarbage); 24 | } 25 | }; 26 | ``` 27 | 28 | 내부 플래그는 Functor로 되어 있는데 `PendingKill`, `InternalGarbage`인지 체크하는 작업을 거치게 됩니다. 29 | 30 | 31 | 32 | 즉 **IsValid는 nullptr인지, 가비지인지, PendingKill인지 살펴보는 작업을 거칩니다.** 33 | 34 | 35 | 36 | ### check, ensure 등의 어써트 (Assert) 37 | 38 | 이런 Assert 함수들은 에디터에서만 동작하는 함수로 안의 내용이 true, false 인지에 따라 동작이 달라지게 됩니다. 이들은 포인터의 operator bool() 연산에 기반해서 결과를 내므로 결론적으로는 nullptr과 비교하는 것과 동일한 결과를 내게 됩니다. 39 | 40 | 41 | 42 | 단 빌드를 하게 되면 해당 코드는 사라지게 됩니다. 43 | -------------------------------------------------------------------------------- /Unreal/Unreal String Classes.md: -------------------------------------------------------------------------------- 1 | ## Fstring & FName & FText 2 | 3 | 위 세가지는 언리얼 엔진에서 문자열들을 처리하는 클래스들 입니다. 이들의 간단한 차이점을 알아두는게 좋습니다. 4 | 5 | ### [FName](https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/FName/) 6 | - 문자열 사용에 있어서 상대적으로 가벼움 7 | + 주어진 문자열이 재사용 되어도 데이터 테이블에 한번만 저장 8 | 9 | - 대소문자 구별 없음 10 | - 한번 지정 후 변경 불가능 11 | - 이런 특징들로 인해 FName을 키로 지정해 찾는 연산이 많음 12 | 13 | 14 | ### [FString](https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/FString/) 15 | - 다른 두 클래스와 다르게 여러 조작이 가능한 클래스 16 | - 여러 검색, 텍스트 조작, Sub String 추출 등의 기능을 제공 17 | - 다른 두개의 클래스보다 상대적으로 무겁습니다. 18 | 19 | 20 | ### [FText](https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/FString/) 21 | 22 | - 로컬라이징을 위한 문자열 클래스입니다. 23 | - UMG 등 여러가지 유저들에게 보이는 텍스트들은 이 클래스를 사용한다고 보시면 됩니다. --------------------------------------------------------------------------------