Publish:

태그: , , , ,

카테고리:


🤯 언리얼을 하기 위해 C++ 기억 되살리기 프로젝트

새로 추가된 STL

  • std::unordered_map (그리고 unordered_multimap)
  • std::unordered_set (그리고 unordered_multiset)
  • std::array

기존의 map, set은 이진 트리 기반 컨테이너 였다. O(log N)
정렬을 해야 했기 때문에.
그렇지만 정렬 필요 없고 접근이 빠른(O(1)) 해시맵, 해시셋의 기능을 하는 게 필요했다.
그래서 생겨났다!

1. 정렬 안된 맵 (unordered_map) + 셋(unordered_set)

  • std::map은 자동으로 정렬되는 컨테이너
  • 그래서 요소 삽입/제거가 빈번할 경우 성능 저하 이슈 우려가 있음

💡 그래서 unordered_map 이 생겨나게 되었다!

  • 키와 값의 쌍(pair)들을 저장
  • 키는 중복 불가
  • 자동으로 정렬되지 않는 컨테이너
    • 요소는 해쉬 함수가 생성하는 색인 (index) 기반의 버킷(bucket)으로 구성됨
    • 해쉬맵(hashmap)이라고도 함
    • (O(1)) 의 속도는 즉 요소가 몇개가 있던 간에 한번에 찾아올 수 있는 속도를 뜻함
    • (O(N)) 의 속도는 N개의 요소 중 어떤 값을 찾으려 할 때 for문 한번 돌려야 한다~ 이게 O(N).

정렬 안 된 셋(set) 도 있음요.
정렬 안 된 맵이랑 거의 같다.

2. 어레이 (array)

  • std::array
  • 전에 만들었던 FixedVector 템플릿 클래스(링크) 와 비슷.
  • 그러나 요소 수를 기억하지 않음
  • 단순히 c스타일 배열을 추상화 한거다~
  • 사이즈 경계 체크는 해줌.

2-1. FixedVector

1
2
3
4
5
6
7
8
9
10
// FixedVector
FixedVector<int, 3> numbers;

numbers.Add(1);

std::cout << numbers.GetSize() << std::endl;
// 하나 넣었으므로 당연히 Size는 1.

std::cout << numbers.GetCapacity() << std::endl;
// 용량이 변하지 않는 FixedVector... 3짜리로 만들었으니 당연히 3.

2-2. std::array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <array>
// ...

std::array<int, 3> numbers;

numbers[0] = 1;

std::cout << numbers.size() << std::endl;
// 3이 출력됨. 지금 어레이에 몇개를 넣었는지 추적하지 않는다.
// 처음 선언할 때 3으로 선언해서 3 나옴.
// FixedVector에서 인덱스 0에 대입한다면, 에러가 날 것. 넣지도 않았으니까...
// 즉, 어레이 3 선언하는 순간 3개 잡아준다는 거다.

std::cout << numbers.max_size() << std::endl;
// 3.

3. 범위 기반 for 반복문

기존의 for 반복문들은…

1
2
3
4
5
6
int scores[3] = { 10, 20, 30 };

for (int i = 0; i < 3; ++i)
{
  std::cout << scores[i] << " " << std::endl;
}

이렇게 인덱스 접근을 하거나.

1
2
3
4
5
6
7
8
9
10
std::map<std::string, int> scoreMap;

scoreMap["Lulu"] = 10;
scoreMap["Coco"] = 50;
scoreMap["Mocha"] = 100;

for (auto it = scoreMap.begin(); it != scoreMap.end(); ++it)
{
  std::cout << it->first << ": " << it->second << std::endl;
}

이렇게 반복자로 접근해왔었음.

하지만 C#에선 foreach로 좀 더 간편하게 반복문을 돌 수 있음.
그걸 배워옴.

1
2
3
4
5
6
7
8
int scores[3] = { 10, 20, 30 };

// 처음부터 끝까지 각 요소별로 score에 대입하면서 반복을 하라.
// 값으로 복사된다는 것 참고!
for (int score : scores)
{
  std::cout << score << " " << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
std::map<std::string, int> scoreMap;

scoreMap["Lulu"] = 10;
scoreMap["Coco"] = 50;
scoreMap["Mocha"] = 100;

// &... 참조형으로 읽어온다!
for (auto& score : scoreMap)
{
  std::cout << it->first << ": " << it->second << std::endl;
}

3-1. for_each()는 어떨까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
  std::unordered_map<std::string, int> scores;

  scores["Lulu"] = 70;
  scores["Chris"] = 50;
  scores["Monica"] = 100;

  // 람다
  auto printElement = [](std::unordered_map<std::string, int>::value_type& item)
  {
    std::cout << item.first << ": " << item.second << std::endl;
  };

  for_each(scores.begin(), scores.end(), printElement);
  // 처음부터 끝까지 printElement 함수 실행해줘라.

  return 0;
}
  • C++03
  • 컨테이너의 각 요소마다 함수를 실행하는 알고리듬
  • 범위 기반 for만큼 가독성이 높진 않다

이슈 및 공부한 것을 기록해두는 개인 블로그 입니다. 댓글, 피드백 환영합니다 🙂

Update:

댓글남기기