"C ++ 컨테이너 선택"이라는 잘 알려진 이미지 (치트 시트)가 있습니다. 원하는 사용법에 가장 적합한 컨테이너를 선택하는 순서도입니다.
이미 C ++ 11 버전이 있는지 아는 사람이 있습니까?
이것은 이전 것입니다 :
"C ++ 컨테이너 선택"이라는 잘 알려진 이미지 (치트 시트)가 있습니다. 원하는 사용법에 가장 적합한 컨테이너를 선택하는 순서도입니다.
이미 C ++ 11 버전이 있는지 아는 사람이 있습니까?
이것은 이전 것입니다 :
답변:
내가 아는 것은 아니지만 텍스트로 할 수 있다고 생각합니다. 또한 차트는 list
일반적으로 그렇게 좋은 컨테이너가 아니기 때문에 차트가 약간 벗어났습니다 forward_list
. 두 목록 모두 틈새 응용 프로그램을위한 매우 특수한 컨테이너입니다.
이러한 차트를 작성하려면 두 가지 간단한 지침이 필요합니다.
성능에 대한 걱정은 일반적으로 처음에는 쓸모가 없습니다. 수천 가지 (또는 그 이상)의 아이템을 다루기 시작할 때 큰 O 고려 사항은 실제로 시작됩니다.
컨테이너에는 두 가지 큰 범주가 있습니다.
find
작업이 있습니다다음은 그 위에 여러 어댑터를 구축 할 수 있습니다 : stack
, queue
, priority_queue
. 여기서는 어댑터를 그대로두고 인식 할 수있을만큼 충분히 전문화되어 있습니다.
질문 1 : 연관성 ?
질문 1.1 : 주문 ?
unordered_
컨테이너를 사용하거나 그렇지 않으면 기존 주문을 사용하십시오.질문 1.2 : 별도의 키 ?
map
과 다른 경우 a를 사용하고 그렇지 않으면 aset
질문 1.3 : 중복 ?
multi
그렇지 않으면을 사용하십시오 .예:
고유 한 ID를 가진 사람이 여러 명 있다고 가정하고 가능한 한 간단하게 ID에서 사람 데이터를 검색하려고합니다.
find
함수, 따라서 연관 컨테이너를 원합니다.
1.1. 나는 주문, 그래서 unordered_
컨테이너에 대해 덜 신경 쓰지 못했습니다.
1.2. 내 키 (ID)는 연관된 값과 별개이므로map
1.3. ID는 고유하므로 복제본이 들어오지 않아야합니다.
최종 답변은 다음과 같습니다 std::unordered_map<ID, PersonData>
.
질문 2 : 메모리가 안정적 입니까?
list
질문 2.1 : 어느 것 ?
list
; a forward_list
는 적은 메모리 풋 프린트에만 유용합니다.질문 3 : 동적 크기 ?
{ ... }
구문을), 다음을 사용 array
. 전통적인 C- 어레이를 대체하지만 편리한 기능으로 대체합니다.질문 4 : 더블 엔드 ?
deque
그렇지 않으면을 사용하십시오 vector
.기본적으로 연관 컨테이너가 필요하지 않은 경우 선택은 vector
입니다. 그것은 Sutter and Stroustrup의 권장 사항 이기도 합니다 .
array
기본 구성 가능한 유형이 필요하지 않습니다. 2) multi
s를 선택하는 것은 복제가 허용되는 것이 아니라 중요 하게 유지 되는지에 관한 것입니다 (비 multi
컨테이너 에 중복을 넣을 수는 있지만 단지 하나만 유지되는 경우).
map.find(key)
는 그보다 훨씬 맛 std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
있어서 의미 론적으로 이는의 find
함수보다는 멤버 함수입니다 <algorithm>
. O (1) 대 O (log n)은 의미에 영향을 미치지 않습니다. 예제에서 "효율적으로"를 제거하고 "쉽게"로 바꾸겠습니다.
deque
이 속성도 가지고 있다고 생각 했습니까?
deque
요소는 안정적 단지 당신이 / 양쪽 끝에 팝업을 밀어 경우; 중간에 삽입 / 삭제를 시작하면 생성 된 간격을 채우기 위해 최대 N / 2 요소가 섞입니다.
Matthieu의 답변이 마음에 들지만 흐름도를 다음과 같이 다시 설명하겠습니다.
기본적으로 컨테이너가 필요한 경우을 사용하십시오 std::vector
. 따라서 다른 모든 컨테이너는에 대한 일부 대체 기능을 제공함으로써 정당화됩니다 std::vector
.
std::vector
항목을 뒤섞을 수 있어야하기 때문에 내용물은 움직일 수 있어야합니다. 이는 (주 기본 생성자가되는 내용에 대한 장소 끔찍한 부담하지 않습니다 필요하지 않습니다 에, 감사 emplace
등). 그러나 대부분의 다른 컨테이너에는 특정 생성자가 필요하지 않습니다 (다시 감사합니다 emplace
). 따라서 이동 생성자 를 절대 구현할 수없는 객체가 있으면 다른 것을 선택해야합니다.
A는 std::deque
의 많은 특성을 갖는 일반적으로 대체 될 것입니다 std::vector
,하지만 당신은 단지 양단 큐의 하나 끝에 삽입 할 수 있습니다. 가운데 인서트는 움직여야합니다. A는 std::list
그 내용에 아무런 요구 사항을 배치하지 않습니다.
std::vector<bool>
아니다. 글쎄, 표준입니다. 그러나 일반적으로 허용 vector
되는 작업 std::vector
은 금지되어 있기 때문에 일반적인 의미 가 아닙니다 . 그리고 그것은 확실히 s를 포함하지 않습니다bool
.
따라서 s vector
컨테이너에서 실제 동작 이 필요 bool
하면에서 가져 오지 않습니다 std::vector<bool>
. 따라서으로 마감해야합니다 std::deque<bool>
.
당신은 컨테이너의 요소를 찾아야하고, 검색 태그 그냥 인덱스 할 수없는 경우에, 당신은 포기해야 할 수도 있습니다 std::vector
에 찬성 set
하고 map
. 키워드 " may "에 유의하십시오 . 정렬 std::vector
은 때때로 합리적인 대안입니다. 또는 Boost.Container 's flat_set/map
는 정렬 된을 구현합니다 std::vector
.
이제 각각 고유 한 요구가있는 네 가지 변형이 있습니다.
map
검색 태그가 원하는 항목과 같지 않은 경우를 사용하십시오 . 그렇지 않으면을 사용하십시오 set
.unordered
당신이있을 때 많은 절대적으로 할 필요가있는 컨테이너의 항목 및 검색 성능 O(1)
보다는 O(logn)
.multi
동일한 검색 태그를 갖는 여러 항목이 필요한 경우 사용하십시오 .특정 비교 작업을 기준으로 항목 컨테이너를 항상 정렬해야하는 경우을 사용할 수 있습니다 set
. 또는 multi_set
동일한 값을 갖기 위해 여러 항목이 필요한 경우.
또는 sorted를 사용할 수 std::vector
있지만 정렬 상태를 유지해야합니다.
반복자와 참조가 무효화되는 경우가 종종 우려됩니다. 다양한 다른 위치에 해당 항목에 대한 반복자 / 포인터가 있도록 항목 목록이 필요한 경우 std::vector
무효화에 대한 접근 방식이 적절하지 않을 수 있습니다. 현재 크기 및 용량에 따라 삽입 작업이 무효화 될 수 있습니다.
std::list
반복자 및 관련 참조 / 포인터는 항목 자체가 컨테이너에서 제거 될 때만 무효화됩니다. std::forward_list
기억이 심각한 문제라면
보증이 너무 강력 std::deque
하면 약하지만 유용한 보증을 제공합니다. 무효화는 중간에 삽입 한 결과이지만 머리 또는 꼬리에 삽입 하면 컨테이너의 항목에 대한 포인터 / 참조가 아닌 반복자 만 무효화 됩니다.
std::vector
끝 부분에 저렴한 삽입 만 제공합니다 (그러면 용량을 불어도 비용이 많이 듭니다).
std::list
성능면에서 비싸지 만 (각각 새로 삽입 된 항목에는 메모리 할당 비용이 들지만) 일관 됩니다. 또한 성능 저하없이 거의 비용을 들이지 않고 아이템을 뒤섞을 수있는 기능을 제공하며 성능 std::list
손실없이 동일한 유형의 다른 컨테이너 와 아이템을 교환 할 수 있습니다 . 많은 것을 섞어 야 하는 경우 사용하십시오 std::list
.
std::deque
머리와 꼬리에 일정한 시간 삽입 / 제거를 제공하지만 중간에 삽입하는 것은 상당히 비쌀 수 있습니다. 따라서 앞면과 뒷면에서 물건을 추가 / 제거 해야하는 경우 필요한 std::deque
것일 수 있습니다.
이동 의미론으로 인해 std::vector
삽입 성능이 예전만큼 나쁘지 않을 수 있습니다. 일부 구현에서는 이동 시맨틱 기반 항목 복사 (소위 "스왑 타이밍")의 형태를 구현했지만 이제는 이동이 언어의 일부이므로 표준에서 요구합니다.
std::array
가능한 적은 동적 할당을 원한다면 훌륭한 컨테이너입니다. C- 어레이를 감싸는 래퍼 일뿐입니다. 즉, 컴파일 타임에 크기를 알아야합니다 . 그걸로 살 수 있다면를 사용하십시오 std::array
.
즉 , 크기를 사용 std::vector
하고 사용 reserve
하면 경계에 대해서도 잘 작동 std::vector
합니다. 이 방법으로 실제 크기는 다를 수 있으며 용량을 날리지 않는 한 하나의 메모리 할당 만 얻을 수 있습니다.
std::sort
, 또한이 std::inplace_merge
쉽게 (라기보다는 새로운 요소를 배치하는 흥미있는 std::lower_bound
+의 std::vector::insert
호출). 에 대해 배울 수있는 좋은 flat_set
와 flat_map
!
vector<bool>
입니다 vector<char>
.
std::allocator<T>
해당 정렬을 지원하지 않는 경우 (그리고 왜 그렇지 않을지 모르겠다면) 항상 사용자 지정 할당자를 사용할 수 있습니다.
std::vector::resize
에는 값을 갖지 않는 과부하가 있습니다 (새로운 크기 만 취하면 새로운 요소가 기본적으로 제 위치에 구성됩니다). 또한 왜 컴파일러가 정렬을 갖도록 선언 된 경우에도 값 매개 변수를 올바르게 정렬 할 수 없습니까?
bitset
사전에 크기를 알고 있다면 bool을 위해 en.cppreference.com/w/cpp/utility/bitset
위 순서도의 C ++ 11 버전은 다음과 같습니다. [원래 저자 Mikael Persson의 저작자 표시없이 게시 됨 ]
여기에는 빠른 스핀이 있지만 아마도 작업이 필요할 것입니다.
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
링크 된 노드가 마음에 들지 않기 때문에 이것이 C ++ 03 버전 과 크게 다르다는 것을 알 수 있습니다 . 링크 된 노드 컨테이너는 드문 경우를 제외하고 일반적으로 링크되지 않은 컨테이너에 의해 성능이 저하 될 수 있습니다. 이러한 상황이 무엇인지 모르고 부스트에 액세스 할 수있는 경우 링크 된 노드 컨테이너를 사용하지 마십시오. (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). 이 목록은 (A) 코드에서 처리하는 것의 99.99 %이며 (B) 많은 요소가 다른 컨테이너가 아닌 사용자 지정 알고리즘을 필요로하기 때문에 주로 소형 및 중간면 컨테이너에 중점을 둡니다.