Ponieważ istnieje mnóstwo odpowiedzi, możesz być zdezorientowany, ale podsumowując:
Użyj std::queue
. Powód jest prosty: jest to struktura FIFO. Chcesz FIFO, używasz std::queue
.
Sprawia, że twój zamiar staje się jasny dla innych, a nawet dla ciebie. A std::list
albo std::deque
nie. Lista może wstawiać i usuwać w dowolnym miejscu, co nie jest tym, co ma robić struktura FIFO, a deque
może dodawać i usuwać z dowolnego końca, czego również nie może zrobić struktura FIFO.
Dlatego powinieneś użyć queue
.
Teraz zapytałeś o wydajność. Po pierwsze, zawsze pamiętaj o tej ważnej zasadzie: najpierw dobry kod, na końcu wydajność.
Powód jest prosty: ludzie, którzy dążą do wydajności przed czystością i elegancją, prawie zawsze kończą pracę na końcu. Ich kod staje się bzdurą, ponieważ porzucili wszystko, co dobre, aby naprawdę nic z tego nie wyciągnąć.
Pisząc najpierw dobry, czytelny kod, większość problemów z wydajnością rozwiąże się sama. A jeśli później stwierdzisz, że brakuje wydajności, możesz teraz łatwo dodać profiler do ładnego, czystego kodu i dowiedzieć się, gdzie jest problem.
To wszystko powiedział, std::queue
to tylko adapter. Zapewnia bezpieczny interfejs, ale używa innego kontenera w środku. Możesz wybrać ten podstawowy kontener, a to zapewnia dużą elastyczność.
Więc jakiego podstawowego kontenera należy użyć? Wiemy, że std::list
i std::deque
obaj zapewniają niezbędne funkcje ( push_back()
, pop_front()
, i front()
), więc jak możemy zdecydować?
Po pierwsze, zrozum, że przydzielanie (i zwalnianie) pamięci nie jest na ogół szybkim zadaniem, ponieważ wymaga wyjścia do systemu operacyjnego i poproszenia go o zrobienie czegoś. A list
musi przydzielać pamięć za każdym razem, gdy coś jest dodawane i zwalniać ją, gdy zniknie.
Z deque
drugiej strony A przydziela porcje. Będzie przydzielać rzadziej niż plik list
. Potraktuj to jako listę, ale każdy fragment pamięci może zawierać wiele węzłów. (Oczywiście sugerowałbym, aby naprawdę nauczyć się, jak to działa ).
Tak więc samo z tym deque
powinno działać lepiej, ponieważ nie radzi sobie tak często z pamięcią. W połączeniu z faktem, że obsługujesz dane o stałym rozmiarze, prawdopodobnie nie będzie trzeba ich przydzielać po pierwszym przejściu przez dane, podczas gdy lista będzie stale alokować i zwalniać.
Drugą rzeczą do zrozumienia jest wydajność pamięci podręcznej . Wychodzenie do pamięci RAM jest powolne, więc gdy procesor naprawdę tego potrzebuje, wykorzystuje ten czas najlepiej, zabierając z powrotem fragment pamięci do pamięci podręcznej. Ponieważ a deque
alokuje w fragmentach pamięci, jest prawdopodobne, że dostęp do elementu w tym kontenerze spowoduje, że procesor CPU przywróci również resztę kontenera. Teraz dalszy dostęp do pliku deque
będzie szybki, ponieważ dane są w pamięci podręcznej.
W przeciwieństwie do listy, na której dane są przydzielane pojedynczo. Oznacza to, że dane mogą być rozproszone po całym miejscu w pamięci, a wydajność pamięci podręcznej będzie niska.
Biorąc to pod uwagę, a deque
powinno być lepszym wyborem. Dlatego jest to domyślny kontener podczas korzystania z pliku queue
. To powiedziawszy, nadal jest to tylko (bardzo) wyedukowane przypuszczenie: będziesz musiał sprofilować ten kod, używając deque
w jednym teście, a list
w drugim, aby naprawdę wiedzieć na pewno.
Ale pamiętaj: spraw, aby kod działał z czystym interfejsem, a następnie martw się o wydajność.
Jan obawia się, że zawinięcie list
lub deque
spowoduje spadek wydajności. Po raz kolejny ani on, ani ja nie możemy powiedzieć na pewno bez profilowania go sami, ale są szanse, że kompilator będzie wbudowywał wywołania, które queue
wykonuje. To znaczy, kiedy powiesz queue.push()
, tak naprawdę powie queue.container.push_back()
, całkowicie pomijając wywołanie funkcji.
Po raz kolejny jest to tylko zgadywanie, ale użycie a queue
nie obniży wydajności w porównaniu z używaniem podstawowego kontenera surowego. Jak powiedziałem wcześniej, używaj queue
, ponieważ jest czysty, łatwy w użyciu i bezpieczny, a jeśli to naprawdę staje się profilem problemu i testem.