{"id":15047357,"url":"https://github.com/doorcs/cpp","last_synced_at":"2026-02-25T10:04:25.131Z","repository":{"id":238846318,"uuid":"797720195","full_name":"doorcs/CPP","owner":"doorcs","description":"Learning modern C++ concepts ( C++14, C++17, C++20 )","archived":false,"fork":false,"pushed_at":"2024-12-17T15:33:06.000Z","size":975,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-13T23:13:33.137Z","etag":null,"topics":["cpp","cpp11","cpp14","cpp17","cpp20"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doorcs.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-08T11:40:48.000Z","updated_at":"2024-12-17T15:33:10.000Z","dependencies_parsed_at":"2024-06-13T17:26:08.020Z","dependency_job_id":"d18f2873-d180-4a5b-a278-5a5b04ea4aeb","html_url":"https://github.com/doorcs/CPP","commit_stats":null,"previous_names":["doorcs/cpp"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doorcs%2FCPP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doorcs%2FCPP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doorcs%2FCPP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doorcs%2FCPP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doorcs","download_url":"https://codeload.github.com/doorcs/CPP/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243495495,"owners_count":20299923,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp11","cpp14","cpp17","cpp20"],"created_at":"2024-09-24T20:57:07.626Z","updated_at":"2026-02-25T10:04:25.125Z","avatar_url":"https://github.com/doorcs.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n\n다른 사람들의 코드를 읽고 이해하는게 상상 이상으로 힘든 일이라는걸 느꼈다.\n같은 일을 하는 코드라도 읽기 편하게 작성하려 노력하자!!\n\n--\u003e\n\n## 기억해야 할 내용들\n- `getline()` 사용 전에 `cin` 객체를 통한 입력을 사용했다면 `cin.ignore()` 꼭 해주기\n  ```cpp\n  int N; cin \u003e\u003e N;\n  cin.ignore()\n  string s; getline(cin, s);\n  ```\n- `char` 타입의 숫자를 `정수형`으로 변환\n  ```cpp\n  char character = '1';\n  int integer = character-'0'; // float, double, long, long long 모두 가능 (정수 값이 캐스팅되는것)\n  ```\n- `vector`를 활용한 이차원 배열 만들기\n  ```cpp\n  int COL = 세로길이(열), ROW = 가로길이(행)\n  vector\u003cvector\u003cint\u003e\u003e brd(COL, vector\u003cint\u003e(ROW)); // `vector\u003cT\u003e vector(size, val=T())`를 중첩\n  ```\n- `fill()`을 활용해 주어진 벡터나 배열을 초기화 (일부 수정도 가능)\n  ```cpp\n  fill(iter, iter, val);\n  // 이터레이터 두 개를 받아서, [inclusive, exclusive) 영역에 val을 채운다\n  \n  int arr[3] = {3, 6, 9}; // 새로 선언할 수 있다면 벡터를 쓰면 되는데, 문제에서 배열이 주어지는 경우가 있다\n  fill(arr, arr+3, 0); // arr = {0, 0, 0}\n\n  vector\u003cint\u003e vec(7, 3);\n  fill(vec.begin()+2, vec.begin()+5, 6); // vec = {3, 3, 6, 6, 6, 3, 3}\n  ```\n- `stringstream` 클래스와 `getline()` 함수를 활용한 split\n  ```cpp\n  string str = \"hello, world!\";\n  stringstream ss(str);\n  while (getline(ss, str, ' ')) {\n    cout \u003c\u003c str \u003c\u003c '\\n'; // str 변수를 재활용\n    // getline() 함수의 세번째 파라미터는 `반드시` char 타입이어야 함 (복잡한 delim 불가)\n  }\n  ```\n- `split()` 구현체\n  ```cpp\n  vector\u003cstring\u003e split(string str, string delim) {\n    str.erase(str.find_last_not_of(\" \\t\\n\\r\\f\\v\")+1); // 뒤쪽 공백 처리를 위한 right-trim\n    vector\u003cstring\u003e ret;\n    size_t fr = 0, rr = str.find(delim); // 기능적 차이는 없지만 int를 쓰면 컴파일 warning\n    while (rr != string::npos) {\n      if (fr != rr) ret.push_back(str.substr(fr, rr - fr)); // delim이 연달아 나오는 케이스 대응\n      fr = rr + delim.size();\n      rr = str.find(delim, fr);\n    }\n    ret.push_back(str.substr(fr)); // delim이 하나도 없을 경우 전체를, 있다면 마지막 덩어리를 담아줌\n    return ret;\n  } // delimiter로 다양한 형태의 문자열을 사용할 수 있다\n  ```\n- 비트마스킹 배열과 `next_permutation()`을 활용한 조합 찾기\n  ```cpp\n  vector\u003cint\u003e num{1, 2, 3, 4, 5, 6, 7, 8, 9}, idx{0, 0, 0, 0, 0, 1, 1, 1, 1}; // 0 먼저 써야함!\n  \n  do {\n    for (int i = 0; i \u003c 9; i++)\n      if (idx[i])\n        cout \u003c\u003c num[i] \u003c\u003c ' '; // {6, 7, 8, 9}에서 {1, 2, 3, 4}까지의 모든 조합을 `역순`으로\n    cout \u003c\u003c '\\n';\n  } while (next_permutation(idx.begin(), idx.end()));  \n  ```\n- 범위 기반 for문을 활용한 입출력 처리\n  ```cpp\n  vector\u003cint\u003e vec1(3);\n  for (int\u0026 it : vec1) cin \u003e\u003e it; // 입력 처리에는 `\u0026`를 붙여야 함 (reference variable)\n  for (int it : vec1) cout \u003c\u003c it \u003c\u003c '\\n'; // for (auto it : vec1) cout \u003c\u003c it \u003c\u003c '\\n';\n\n  vector\u003cpair\u003cint, int\u003e\u003e vec2(5);\n  for (auto\u0026 [a, b] : vec2) cin \u003e\u003e a \u003e\u003e b; // (C++17) structured binding - 앞에 auto 붙여주기!!\n  for (const auto [a, b] : vec2) cout \u003c\u003c a \u003c\u003c ' ' \u003c\u003c b \u003c\u003c '\\n'; // 출력은 `\u0026`가 없어도 됨\n  ```\n- `\u003calgorithm\u003e` 헤더 제공 함수들에서 *initializer_list 클래스*`{}` 활용\n  ```cpp\n  int val1 = 9999, val2 = 3210, val3 = -2147483648;\n  cout \u003c\u003c min({val1, val2, val3}) \u003c\u003c ' ' \u003c\u003c max({val1, val2, val3});\n  // cout \u003c\u003c min(val1, min(val2, val3)) \u003c\u003c ' ' \u003c\u003c max(val1, max(val2, val3));\n  ```\n- `비트 연산자`를 활용한 효율적인 `홀수` / 짝수 판별\n  ```cpp\n  int even = 2, odd = 3;\n  if (odd\u00261) cout \u003c\u003c \"odd\"; // 홀수와 \u00261하면 결과값이 1, true (비트패턴은 마지막 비트만 1)\n  if (!(even\u00261)) cout \u003c\u003c \"even\"; // 짝수와 \u00261 하면 결과값이 0, false (비트패턴은 모든 비트가 0)\n  // 짝수 판정은 반드시 두 번 이상의 연산이 필요하지만, 홀수 판정은 `\u00261`로 한 번의 연산에 처리할 수 있다\n  ```\n## STL 컨테이너 사용법 정리\n\n- 컨테이너 공통:\n  - .size() 메서드로 현재 담아두고 있는 요소의 수를 알 수 있음\n  - .empty() 메서드로 현재 컨테이너가 비어있는지 알 수 있음\n  - 컨테이너 생성 시점에 값들을 모두 알 수 있다면, initializer_list 생성자를 활용할 수 있음\n\n- 문자열 ( `std::string` )\n  ```cpp\n  string str;\n  // cin \u003e\u003e str; // cin을 통한 입력도 가능\n  // cin.ignore() \u003c\u003c- 입력 처리에 cin 객체를 활용했다면, getline() 함수 사용 전에 cin.ignore() 필요\n  getline(cin, str); // getline() 함수를 통해, 공백을 포함한 한 줄 입력을 string에 담을 수 있다\n  // std::getline() 함수는 \u003cstring\u003e 헤더에 있다!\n\n  // 자르기 ( Substring )\n  string sub = str.substr(start, count); // start 인덱스로부터 count개를 선택한 substring\n  // str.substr(0, 3); \u003c\u003c- {0번째, 1번째, 2번째} 인덱스, 즉 {첫번째, 두번째, 세번째} 문자를 담아 return\n\n  // 오른쪽 공백 제거 ( Right Trim )\n  str.erase(str.find_last_not_of(\" \\t\\n\\r\\f\\v\") + 1);\n  // str.erase(find_last_not_of(\"0x20 | 0x09 | 0x0a | 0x0d | 0x0c | 0x0b\")+1);\n  // find_last_not_of()는 문자열이 모두 공백일 경우 string::npos를 반환하므로 +1을 해주면 0이 되는데,\n  // str.erase(0)은 str.erase(0, string::npos)와 같고, 문자열을 모두 지운다\n    \n  // 왼쪽 공백 제거 ( Left Ttrim )\n  str.erase(0, str.find_first_not_of(\" \\t\\n\\r\\f\\v\"));\n  // find_first_not_of()는 문자열이 모두 공백(whitespace character)일 경우 string::npos를 반환하므로\n  // str.erase(0, string::npos)가 호출되어 문자열을 모두 지운다\n  ```\n- 맵 ( `std::map` )\n  ```cpp\n  map\u003cT, U\u003e mp; // map\u003cT, U\u003e mp{{key1, val1}, {key2, val2}};\n  // key-value 매핑에 사용함. 내부적으로 pair\u003cT, U\u003e를 사용하며 key의 `operator\u003c`를 적용해 오름차순으로 정렬함\n  mp[key] = val; // 존재하지 않는 key에 접근하면 U의 기본 생성자가 호출되어 {key, val} 쌍을 map에 insert함\n  mp[key]++; // map\u003cint, int\u003e일 경우, {key, 0} -\u003e `++` -\u003e 최종적으로 {key, 1}가 map에 insert됨\n  .find(key); // find 메서드를 통해 특정 key의 존재 여부를 확인할 수 있음 - 존재하지 않을 경우 .end() 반환\n  // .contains() 메서드가 더 직관적이지만, C++20 feature이므로 find 메서드에 익숙해지기\n  ```\n- 해시맵 ( `std::unordered_map` )\n  ```cpp\n  unordered_map\u003cT, U\u003e mp; // unordered_map\u003cT, U\u003e mp{{key1, val1}, {key2, val2}};\n  // map과 비슷하지만 Hashing 방식으로 동작해 요소 접근의 시간복잡도가 O(1)\n  // 단, key로 사용할 타입은 반드시 1. hash function, 2. equality check 두가지를 가지고 있어야 함\n  // primitive types, string 정도만 key로 사용하는게 좋을 듯 (사용자 정의 객체를 key로 쓰려면 귀찮다)\n  ```\n- 셋 ( `std::set` )\n  ```cpp\n  set\u003cT\u003e s; // set\u003cT\u003e s{val1, val2, val3};\n  // 포함 여부를 확인해야 할 때 시간복잡도를 줄일 수 있으며, 원소들의 uniqueness를 보장\n  .insert(val); // insert 메서드를 통해 값을 추가하려고 `시도`할 수 있음 - 값이 이미 존재할 경우 무시됨\n  .find(val); // find 메서드를 통해 특정 값의 존재 여부를 확인할 수 있음 - 존재하지 않을 경우 .end() 반환\n  ```\n- 리스트 ( `std::list` )\n  ```cpp\n  list\u003cT\u003e li; // list\u003cT\u003e li{val1, val2, val3};\n  // [] 연산자를 지원하지 않아, 요소를 다룰 때 iterator를 사용해야 함\n  // .begin() 이터레이터를 활용하는 방식이 가장 직관적임\n  auto it = li.begin();\n  cout \u003c\u003c *it; // 첫번째 요소 참조\n  for (int i = 0; i \u003c N; i++) it++; // advance(it, N) 와 같다\n  cout \u003c\u003c *it; // N+1번째 요소 참조 (N이 2일 경우, 3번째 요소 참조)\n\n  .insert(pos, val); // 이때 pos는 이터레이터. 새로 들어온 원소가 pos번째 원소가 됨\n  .erase(pos); // 삭제된 원소 다음 원소를 가리키는 이터레이터를 return함. insert와 함께 사용할 수 있음\n  li.insert(li.erase(it), val); // it자리에 원래 있던 원소를 삭제하고, val로 대체함\n  ```\n- 벡터, 동적 배열 ( `std::vector` )\n  ```cpp\n  vector\u003cT\u003e v; // vector\u003cT\u003e v{val1, val2, val3};\n  // 동적 배열. 생성자를 호출 시 크기를 지정하지 않으면 기본 size와 capacity는 모두 0\n  // push_back(), pop_back(), back() 세가지 연산으로 스택을 대체할 수 있음 (기능이 더 많아서 편리하다)\n  .push_back(val); // 현재 요소들의 끝에 추가. stack.push() 대체 가능\n  .pop_back(); // stack.pop() 대체 가능\n  .back(); // stack.top() 대체 가능\n  // .insert(pos, val) - insert 연산이 필요할 경우 vector 대신 list 쓰기\n  vector\u003cint\u003e v(10);\n  for (int\u0026 it : v) cin \u003e\u003e it; // for (auto\u0026 it : v) 도 가능\n  ```\n- 덱 ( `std::deque` )\n  ```cpp\n  deque\u003cT\u003e dq;\n  .push_front(val);\n  .pop_front();\n  .push_back();\n  .pop_back();\n  // 뒤집는 연산이 필요할 때, 실제로 순서를 뒤집는 대신 반대로 순회하도록 할 수 있다\n  ```\n- 큐 ( `std::queue` )\n  ```cpp\n  queue\u003cT\u003e q;\n  .front();\n  .push(val);\n  .pop();\n  ```\n- 우선순위 큐 ( `std::priority_queue` )\n  ```cpp\n  priority_queue\u003cT\u003e pq;\n  .top(); // .front()가 아니라 .top()이다! top priority!!\n  .push();\n  .pop();\n  ```\n## 언젠가 고쳤던 좋지 않은 습관들\n\n- 줄바꿈이 필요할 땐 `std::endl` 대신 `'\\n'` 사용\n- `cin.tie(nullptr)-\u003eios_base::sync_with_stdio(false);` 처럼 쓰지 말고 분리하기\n  ```cpp\n    cin.tie(nullptr);\n    cout.tie(nullptr);\n    ios_base::sync_with_stdio(false);\n  ```\n- `for`, `while` 같은 제어문 키워드와 조건식 `괄호` 사이는 `한` `칸` 띄워주기\n  ```cpp\n    for(;;) // bad\n    for (;;) // good!\n  ```\n\u003c!-- google styleguide! --\u003e\n- `if`, `else if`, `else` 구문 정렬 - `closing brace on new line, else on same line`\n  ```cpp\n    if (cond1) {\n      // \n    } else if (cond2) { // good!  \n      //\n    } else {\n      //\n    }\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoorcs%2Fcpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoorcs%2Fcpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoorcs%2Fcpp/lists"}