Kontenery standardowej biblioteki C++
Biblioteka Standardowa udostępnia różne kontenery bezpieczne dla typów do przechowywania kolekcji powiązanych obiektów. Kontenery to szablony klas. Podczas deklarowania zmiennej kontenera należy określić typ elementów, które będą przechowywane w kontenerze. Kontenery można tworzyć z listami inicjatorów. Mają one funkcje składowe do dodawania i usuwania elementów oraz wykonywania innych operacji.
Iteracja elementów w kontenerze i uzyskiwanie dostępu do poszczególnych elementów przy użyciu iteratorów. Iteratory można jawnie używać przy użyciu ich funkcji składowych i operatorów oraz funkcji globalnych. Można ich również używać niejawnie, na przykład za pomocą pętli range-for. Iteratory dla wszystkich kontenerów biblioteki standardowej języka C++ mają wspólny interfejs, ale każdy kontener definiuje własne wyspecjalizowane iteratory.
Kontenery można podzielić na trzy kategorie: kontenery sekwencji, kontenery kojarzące i karty kontenerów.
Kontenery sekwencji
Kontenery sekwencji zachowują kolejność wstawionych elementów, które określisz.
Kontener zachowuje się jak tablica vector
, ale może automatycznie rosnąć zgodnie z potrzebami. Jest to dostęp losowy i stale przechowywany, a długość jest wysoce elastyczna. Z tych powodów i nie tylko vector
jest preferowanym kontenerem sekwencji dla większości aplikacji. W razie wątpliwości co do rodzaju kontenera sekwencji do użycia, zacznij od użycia wektora! Aby uzyskać więcej informacji, zobacz vector
Klasa.
Kontener array
ma pewne mocne strony vector
, ale długość nie jest tak elastyczna. Aby uzyskać więcej informacji, zobacz array
Klasa.
deque
Kontener (kolejka podwójna) umożliwia szybkie wstawianie i usuwanie na początku i na końcu kontenera. Udostępnia ona losowe i elastyczne zalety programu vector
, ale nie jest ciągłe. Aby uzyskać więcej informacji, zobacz deque
Klasa.
list
Kontener to podwójnie połączona lista, która umożliwia dostęp dwukierunkowy, szybkie wstawianie i szybkie usuwanie w dowolnym miejscu w kontenerze, ale nie można losowo uzyskać dostępu do elementu w kontenerze. Aby uzyskać więcej informacji, zobacz list
Klasa.
forward_list
Kontener jest listą połączoną ze singly — wersją dostępu do przodu programu list
. Aby uzyskać więcej informacji, zobacz forward_list
Klasa.
Kontenery asocjacyjne
W kontenerach asocjacyjnych elementy są wstawiane wstępnie zdefiniowanej kolejności — na przykład jako posortowane rosnąco. Dostępne są również nieurządzane kontenery asocjacyjne. Kontenery asocjacyjne można zgrupować w dwa podzestawy: mapy i zestawy.
Element map
, czasami nazywany słownikiem, składa się z pary klucz/wartość. Klucz jest używany do zamawiania sekwencji, a wartość jest skojarzona z tym kluczem. Na przykład element map
może zawierać klucze reprezentujące każde unikatowe słowo w tekście i odpowiadające im wartości reprezentujące liczbę wystąpień każdego wyrazu w tekście. Nieurządkowana wersja elementu map
to unordered_map
. Aby uzyskać więcej informacji, zobacz map
Class and Class (Klasa i unordered_map
klasa).
A set
to tylko rosnący kontener unikatowych elementów — wartość jest również kluczem. Nieurządkowana wersja elementu set
to unordered_set
. Aby uzyskać więcej informacji, zobacz set
Class and Class (Klasa i unordered_set
klasa).
Oba map
elementy i set
zezwalają tylko na wstawianie jednego wystąpienia klucza lub elementu do kontenera. Jeśli wymagane jest wiele wystąpień elementów, użyj polecenia multimap
lub multiset
. Nieurządkowane wersje to unordered_multimap
i unordered_multiset
. Aby uzyskać więcej informacji, zobacz multimap
Klasa, unordered_multimap
Klasa, multiset
Klasa i unordered_multiset
Klasa.
Uporządkowane mapy i zestawy obsługują iteratory dwukierunkowe, a ich nieuordowane odpowiedniki obsługują iteratory przesyłania dalej. Aby uzyskać więcej informacji, zobacz Iteratory.
Heterogeniczne wyszukiwanie w kontenerach asocjacyjnych (C++14)
Uporządkowane kontenery asocjacyjne (mapowanie, multimapa, zestaw i multiset) obsługują teraz heterogeniczne wyszukiwanie, co oznacza, że nie trzeba już przekazywać dokładnie tego samego typu obiektu co klucz lub element w funkcjach składowych, takich jak find()
i lower_bound()
. Zamiast tego można przekazać dowolny typ, dla którego zdefiniowano przeciążony operator<
element, który umożliwia porównanie z typem klucza.
Wyszukiwanie heterogeniczne jest włączone na zasadzie zgody podczas określania std::less<>
komparatora lub std::greater<>
"functor diamentu" podczas deklarowania zmiennej kontenera, jak pokazano poniżej:
std::set<BigObject, std::less<>> myNewSet;
Jeśli używasz domyślnego komparatora, kontener zachowuje się dokładnie tak samo jak w języku C++11 i starszych wersjach.
W poniższym przykładzie pokazano, jak przeciążyć operator<
, aby umożliwić użytkownikom std::set
wyszukiwanie, po prostu przekazując mały ciąg, który można porównać z elementem członkowskim każdego obiektu BigObject::id
.
#include <set>
#include <string>
#include <iostream>
#include <functional>
using namespace std;
class BigObject
{
public:
string id;
explicit BigObject(const string& s) : id(s) {}
bool operator< (const BigObject& other) const
{
return this->id < other.id;
}
// Other members....
};
inline bool operator<(const string& otherId, const BigObject& obj)
{
return otherId < obj.id;
}
inline bool operator<(const BigObject& obj, const string& otherId)
{
return obj.id < otherId;
}
int main()
{
// Use C++14 brace-init syntax to invoke BigObject(string).
// The s suffix invokes string ctor. It is a C++14 user-defined
// literal defined in <string>
BigObject b1{ "42F"s };
BigObject b2{ "52F"s };
BigObject b3{ "62F"s };
set<BigObject, less<>> myNewSet; // C++14
myNewSet.insert(b1);
myNewSet.insert(b2);
myNewSet.insert(b3);
auto it = myNewSet.find(string("62F"));
if (it != myNewSet.end())
cout << "myNewSet element = " << it->id << endl;
else
cout << "element not found " << endl;
// Keep console open in debug mode:
cout << endl << "Press Enter to exit.";
string s;
getline(cin, s);
return 0;
}
//Output: myNewSet element = 62F
Następujące funkcje składowe w mapie, wielomapie, zestawie i wielozestawie zostały przeciążone w celu obsługi wyszukiwania heterogenicznego:
find
count
lower_bound
upper_bound
equal_range
Adaptery kontenerów
Adapter kontenera to odmiana sekwencji lub kontenera kojarzącego, który ogranicza interfejs dla uproszczenia i jasności. Karty kontenerów nie obsługują iteratorów.
queue
Kontener jest zgodny z semantyką FIFO (najpierw w pierwszej kolejności). Pierwszy element wypchnięty — czyli wstawiony do kolejki — jest pierwszym elementem, który ma zostać zwinięty — czyli usuniętym z kolejki. Aby uzyskać więcej informacji, zobacz queue
Klasa.
priority_queue
Kontener jest zorganizowany tak, aby element, który ma najwyższą wartość, zawsze był pierwszy w kolejce. Aby uzyskać więcej informacji, zobacz priority_queue
Klasa.
stack
Kontener jest zgodny z semantykami LIFO (ostatni w, pierwszy na wyjęcie). Ostatnim elementem wypchniętym na stos jest pierwszy element zwinięty. Aby uzyskać więcej informacji, zobacz stack
Klasa.
Ponieważ karty kontenerów nie obsługują iteratorów, nie mogą być używane z algorytmami biblioteki standardowej języka C++. Aby uzyskać więcej informacji, zobacz Algorytmy.
Wymagania dotyczące elementów kontenera
Ogólnie rzecz biorąc, elementy wstawione do kontenera biblioteki standardowej języka C++ mogą być niemal dowolnym typem obiektu, jeśli można je skopiować. Elementy tylko wymienne — na przykład te, które vector<unique_ptr<T>>
są tworzone przy użyciu, unique_ptr<>
będą działać tak długo, jak nie wywołujesz funkcji składowych, które próbują je skopiować.
Destruktor nie może zgłosić wyjątku.
Uporządkowane kontenery asocjacyjne — opisane wcześniej w tym artykule — muszą mieć zdefiniowany operator porównania publicznego. Domyślnie operator to operator<
, ale obsługiwane są nawet typy, z którymi nie działają operator<
.
Niektóre operacje na kontenerach mogą również wymagać publicznego konstruktora domyślnego i publicznego operatora równoważności. Na przykład kontenery asocjacyjne nieurządzane wymagają obsługi równości i tworzenia skrótów.
Uzyskiwanie dostępu do elementów kontenera
Dostęp do elementów kontenerów jest uzyskiwany przy użyciu iteratorów. Aby uzyskać więcej informacji, zobacz Iteratory.
Uwaga
Można również używać pętli opartych na zakresie do iterowania kolekcji biblioteki standardowej języka C++.
Porównywanie kontenerów
Wszystkie kontenery przeciążą operator== do porównywania dwóch kontenerów tego samego typu, które mają ten sam typ elementu. Można użyć == do porównania ciągu wektorowego z innym ciągiem> wektorowym<, ale nie można go użyć do porównania ciągu> wektorowego<<z ciągiem> listy<lub ciągiem> wektorowym<<*>.> W języku C++98/03 można użyć std::equal
polecenia lub std::mismatch
porównać różne typy kontenerów i/lub typów elementów. W języku C++11 można również użyć polecenia std::is_permutation
. Jednak we wszystkich tych przypadkach funkcje zakładają, że kontenery mają taką samą długość. Jeśli drugi zakres jest krótszy niż pierwszy, wyniki zachowania niezdefiniowanego. Jeśli drugi zakres jest dłuższy, wyniki mogą być nadal nieprawidłowe, ponieważ porównanie nigdy nie będzie kontynuowane poza końcem pierwszego zakresu.
Porównywanie niepodobnych kontenerów (C++14)
W języku C++14 lub nowszym można porównać różne kontenery i/lub różne typy elementów przy użyciu jednego z std::equal
przeciążeń funkcji , std::mismatch
lub std::is_permutation
funkcji, które przyjmują dwa kompletne zakresy. Te przeciążenia umożliwiają porównywanie kontenerów o różnych długościach. Te przeciążenia są znacznie mniej podatne na błędy użytkownika i są zoptymalizowane pod kątem zwracania wartości false w stałym czasie, gdy kontenery o różnej długości są porównywane. W związku z tym zalecamy użycie tych przeciążeń, chyba że masz wyraźny powód, aby nie lub używasz kontenera, który nie korzysta z optymalizacji z podwójnym zakresem std::list
.
Zobacz też
Kontenery równoległe
<sample container>
Bezpieczeństwo wątku w standardowej bibliotece C++