Udostępnij za pośrednictwem


Kolekcje (C++/CX)

W programie C++/CX można bezpłatnie korzystać z kontenerów standardowej biblioteki szablonów (STL) lub dowolnego innego typu kolekcji zdefiniowanego przez użytkownika. Jednak w przypadku przekazywania kolekcji w środowisko wykonawcze systemu Windows interfejs binarny aplikacji (ABI) — na przykład do kontrolki XAML lub klienta JavaScript — należy użyć środowisko wykonawcze systemu Windows typów kolekcji.

Środowisko wykonawcze systemu Windows definiuje interfejsy kolekcji i powiązanych typów, a C++/CX udostępnia konkretne implementacje języka C++ w pliku nagłówkowym collection.h. Na tej ilustracji przedstawiono relacje między typami kolekcji:

Diagram drzewa dziedziczenia C plus C X dla typów kolekcji.

Użycie wektorów

Jeśli klasa musi przekazać kontener sekwencji do innego składnika środowisko wykonawcze systemu Windows, użyj polecenia Windows::Foundation::Collections:: IVector<T> jako parametru lub zwracanego typu oraz platform::Collections::Vector<T> jako konkretnej implementacji. Jeśli spróbujesz użyć Vector typu w publicznej wartości zwracanej lub parametrze, zostanie zgłoszony błąd kompilatora C3986. Możesz rozwiązać ten problem, zmieniając Vector element na IVector.

Ważne

Jeśli przekazujesz sekwencję w ramach własnego programu, użyj metody Vector lub std::vector , ponieważ są one bardziej wydajne niż IVector. Używaj IVector tylko wtedy, gdy przekazujesz kontener w usłudze ABI.

System typów środowisko wykonawcze systemu Windows nie obsługuje koncepcji tablic postrzępionych i dlatego nie można przekazać IVector<Platform::Array<T>> jako wartości zwracanej lub parametru metody. Aby przekazać tablicę postrzępionych lub sekwencję sekwencji w usłudze ABI, użyj polecenia IVector<IVector<T>^>.

Vector<T> Udostępnia metody wymagane do dodawania, usuwania i uzyskiwania dostępu do elementów w kolekcji oraz niejawnie konwertowane na IVector<T>. Można również używać algorytmów STL w wystąpieniach programu Vector<T>. W poniższym przykładzie pokazano pewne podstawowe użycie. Funkcja begin i end znajdują się tutaj w Platform::Collections przestrzeni nazw, a nie z std przestrzeni nazw.

#include <collection.h>
#include <algorithm>
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;


void Class1::Test()
{
    Vector<int>^ vec = ref new Vector<int>();
    vec->Append(1);
    vec->Append(2);
    vec->Append(3);
    vec->Append(4);
    vec->Append(5);


    auto it = 
        std::find(begin(vec), end(vec), 3);

    int j = *it; //j = 3
    int k = *(it + 1); //or it[1]

    // Find a specified value.
    unsigned int n;         
    bool found = vec->IndexOf(4, &n); //n = 3

    // Get the value at the specified index.
    n = vec->GetAt(4); // n = 3

    // Insert an item.
    // vec = 0, 1, 2, 3, 4, 5
    vec->InsertAt(0, 0);

    // Modify an item.
    // vec = 0, 1, 2, 12, 4, 5,
    vec->SetAt(3, 12);

    // Remove an item.
    //vec = 1, 2, 12, 4, 5 
    vec->RemoveAt(0);

    // vec = 1, 2, 12, 4
    vec->RemoveAtEnd();

    // Get a read-only view into the vector.
    IVectorView<int>^ view = vec->GetView();
}

Jeśli masz istniejący kod, który używa std::vector metody i chcesz użyć go ponownie w składniku środowisko wykonawcze systemu Windows, wystarczy użyć jednego z Vector konstruktorów, który przyjmuje std::vector iteratory lub parę iteratorów do konstruowania Vector w punkcie, w którym przekazujesz kolekcję w usłudze ABI. W poniższym przykładzie pokazano, jak używać konstruktora przenoszenia do wydajnego Vector inicjowania z klasy std::vector. Po operacji przenoszenia oryginalna vec zmienna nie jest już prawidłowa.

//#include <collection.h>
//#include <vector>
//#include <utility> //for std::move
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
//using namespace std;
IVector<int>^ Class1::GetInts()
{
    vector<int> vec;
    for(int i = 0; i < 10; i++)
    {
        vec.push_back(i);
    }    
    // Implicit conversion to IVector
    return ref new Vector<int>(std::move(vec));
}

Jeśli w pewnym momencie masz wektor ciągów, które należy przekazać przez usługę ABI w przyszłości, musisz zdecydować, czy początkowo utworzyć ciągi jako std::wstring typy, czy jako Platform::String^ typy. Jeśli musisz wykonać wiele czynności przetwarzania w ciągach, użyj polecenia wstring. W przeciwnym razie utwórz ciągi jako Platform::String^ typy i unikaj ich późniejszego konwertowania. Należy również zdecydować, czy umieścić te ciągi w std:vector obiekcie , czy Platform::Collections::Vector wewnętrznie. Ogólnie rzecz biorąc, należy użyć elementu std::vector , a następnie utworzyć go Platform::Vector tylko wtedy, gdy przekazujesz kontener w usłudze ABI.

Typy wartości w wektorze

Każdy element, który ma być przechowywany w elemecie Platform::Collections::Vector , musi obsługiwać porównywanie równości, niejawnie lub przy użyciu niestandardowego modułu std::equal_to , który podajesz. Wszystkie typy odwołań i wszystkie typy skalarne niejawnie obsługują porównania równości. W przypadku typów wartości innych niż skalarne, takich jak Windows::Foundation::D ateTime lub dla porównań niestandardowych — na przykład objA->UniqueID == objB->UniqueID— należy podać obiekt funkcji niestandardowej.

Elementy VectorProxy

Platform::Collections::VectorIterator i Platform::Collections::VectorViewIterator umożliwiają korzystanie range for z pętli i algorytmów, takich jak std::sort z kontenerem IVector<T>. Nie można jednak IVector uzyskać dostępu do elementów za pośrednictwem wyłudżenia wskaźnika języka C++. Dostęp do nich można uzyskać tylko za pośrednictwem metod GetAt i SetAt . W związku z tym te iteratory używają klas Platform::Details::VectorProxy<T> proxy i Platform::Details::ArrowProxy<T> zapewniają dostęp do poszczególnych elementów za pośrednictwem *operatorów , ->, i [], zgodnie z wymaganiami biblioteki standardowej. Ściśle rzecz biorąc, biorąc pod uwagę IVector<Person^> vec, typ *begin(vec) to VectorProxy<Person^>. Jednak obiekt proxy jest prawie zawsze niewidoczny dla kodu. Te obiekty serwera proxy nie są udokumentowane, ponieważ są przeznaczone tylko do użytku wewnętrznego przez iteratory, ale warto wiedzieć, jak działa mechanizm.

Jeśli używasz pętli opartej na for zakresie dla IVector kontenerów, użyj polecenia auto&& , aby umożliwić zmiennej iteratora prawidłowe powiązanie z elementami VectorProxy . Jeśli używasz auto&polecenia , zostanie zgłoszone ostrzeżenie kompilatora C4239 i VectoryProxy zostanie wymienione w tekście ostrzegawczym.

Poniższa ilustracja przedstawia pętlę range for na obiekcie IVector<Person^>. Zwróć uwagę, że wykonanie zostało zatrzymane w punkcie przerwania w wierszu 64. Okno QuickWatch pokazuje, że zmienna iteratora jest w rzeczywistości zmienną p zawierającą VectorProxy<Person^>m_v zmienne składowe i m_i . Jednak wywołanie GetType tej zmiennej powoduje zwrócenie identycznego Person typu do wystąpienia p2. Na wynos jest to, że chociaż VectorProxy i ArrowProxy może występować w QuickWatch, debugerze niektórych błędów kompilatora lub innych miejscach, zwykle nie trzeba jawnie kodować dla nich.

Zrzut ekranu przedstawiający debugowanie elementu VectorProxy w pętli opartej na zakresie.

Jednym ze scenariuszy, w którym trzeba kodować wokół obiektu proxy, jest dynamic_cast wykonanie elementu na elementach — na przykład w przypadku wyszukiwania obiektów XAML określonego typu w UIElement kolekcji elementów. W takim przypadku należy najpierw rzutować element na platform::Object^, a następnie wykonać rzutowanie dynamiczne:

void FindButton(UIElementCollection^ col)
{
    // Use auto&& to avoid warning C4239
    for (auto&& elem : col)
    {
        Button^ temp = dynamic_cast<Button^>(static_cast<Object^>(elem));
        if (nullptr != temp)
        {
            // Use temp...
        }
    }
}

Mapuj użycie

W tym przykładzie pokazano, jak wstawić elementy i wyszukać je w typie Platform::Collections::Map, a następnie zwrócić element Map jako tylko do odczytu windows::Foundation::Collections::IMapView .

//#include <collection.h>
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
IMapView<String^, int>^ Class1::MapTest()
{
    Map<String^, int>^ m = ref new Map<String^, int >();
    m->Insert("Mike", 0);
    m->Insert("Dave", 1);
    m->Insert("Doug", 2);
    m->Insert("Nikki", 3);
    m->Insert("Kayley", 4);
    m->Insert("Alex", 5);
    m->Insert("Spencer", 6);

   // PC::Map does not support [] operator
   int i = m->Lookup("Doug");
   
   return m->GetView();
   
}

Ogólnie rzecz biorąc, w przypadku funkcji wewnętrznej mapy preferuj std::map typ ze względów wydajności. Jeśli musisz przekazać kontener w usłudze ABI, skonstruuj obiekt Platform::Collections::Map z pliku std::map i zwróć go Map jako element Windows::Foundation::Collections::IMap. Jeśli spróbujesz użyć Map typu w publicznej wartości zwracanej lub parametrze, zostanie zgłoszony błąd kompilatora C3986. Możesz rozwiązać ten problem, zmieniając Map element na IMap. W niektórych przypadkach — na przykład jeśli nie wykonujesz dużej liczby odnośników lub wstawiania, a często przekazujesz kolekcję w usłudze ABI — może to być tańsze w użyciu Platform::Collections::Map od początku i uniknięcie kosztów konwersji std::mapelementu . W każdym razie należy unikać operacji wyszukiwania i wstawiania na obiekcie IMap , ponieważ są one najmniej wydajne dla trzech typów. Przekonwertuj wartość na IMap tylko w momencie przekazania kontenera w usłudze ABI.

Typy wartości w mapie

Elementy w elemecie Platform::Collections::Map są uporządkowane. Każdy element, który ma być przechowywany w obiekcie Map , musi obsługiwać mniej niż porównanie ze ścisłym słabym porządkoweniem, niejawnie lub przy użyciu niestandardowego modułu stl::less , który podajesz. Typy skalarne obsługują porównanie niejawnie. W przypadku typów wartości innych niż skalarne, takich jak Windows::Foundation::DateTime, lub dla porównań niestandardowych — na przykład objA->UniqueID < objB->UniqueID— należy podać niestandardowy komparator.

Typy kolekcji

Kolekcje dzielą się na cztery kategorie: modyfikowalne wersje i wersje tylko do odczytu kolekcji sekwencji i kolekcje asocjacyjne. Ponadto język C++/CX rozszerza kolekcje, zapewniając trzy klasy iteracyjne, które upraszczają dostęp do kolekcji.

Elementy kolekcji modyfikowalnej można zmienić, ale elementy kolekcji tylko do odczytu, znanej jako widok, mogą być odczytywane tylko. Dostęp do elementów kolekcji Platform::Collections::Vector lubPlatform::Collections::VectorView można uzyskać za pomocą iteratora lub kolekcji Vector::GetAt i indeksu. Dostęp do elementów kolekcji asocjacyjnej można uzyskać przy użyciu kolekcji Map::Lookup i klucza.

Platform::Collections::Map, klasa
Kolekcja asocjacyjna, modyfikowalna. Elementy mapy to pary klucz-wartość. Wyszukanie klucza w celu pobrania skojarzonej wartości i iterowanie wszystkich par klucz-wartość jest obsługiwane.

Map i MapView są szablony w systemie <K, V, C = std::less<K>>; w związku z tym można dostosować komparator. Ponadto element i Vector są szablonamiVectorView, <T, E = std::equal_to<T>> dzięki czemu można dostosować zachowanie elementu IndexOf(). Jest to ważne głównie dla VectorVectorView i struktur wartości. Aby na przykład utworzyć wektor<Windows::Foundation::D ateTime>, należy podać niestandardowy komparator, ponieważ funkcja DateTime nie przeciąża operatora ==.

Platform::Collections::MapView, klasa
Wersja tylko do odczytu obiektu Map.

Platform::Collections::Vector, klasa
Kolekcja sekwencji modyfikowalna. Vector<T> obsługuje dostęp losowy w czasie stałym oraz operacje dołączania w amortyzowanym stałym czasie.

Platform::Collections::VectorView, klasa
Wersja tylko do odczytu obiektu Vector.

Platform::Collections::InputIterator, klasa
Iterator STL spełniający wymagania iteratora wejściowego STL.

Platform::Collections::VectorIterator, klasa
Iterator STL spełniający wymagania iteratora ZTL modyfikowalnego losowego dostępu.

Platform::Collections::VectorViewIterator, klasa
Iterator STL spełniający wymagania iteratora dostępu losowego STL const .

funkcje begin() i end()

Aby uprościć korzystanie z biblioteki STL do przetwarzania Vectorobiektów , , VectorView, MapMapViewi dowolnychWindows::Foundation::Collections, język C++/CX obsługuje przeciążenia funkcji begin i funkcji końcowej, które nie są elementami składowymi.

W poniższej tabeli wymieniono dostępne iteratory i funkcje.

Iteratory Funkcje
Platform::Collections::VectorIterator<T>

(Magazyny wewnętrzneWindows::Foundation::Collections:: IVector<T> i int).
begin/ end(Windows::Foundation::Collections:: IVector<T>)
Platform::Collections::VectorViewIterator<T>

(Magazyny wewnętrzneIVectorView<T>^ i int).
begin/ end (IVectorView<T>^)
Platform::Collections::InputIterator<T>

(Magazyny wewnętrzneIIterator<T>^ i T.)
begin/ end (IIterable<T>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Magazyny wewnętrzneIIterator<T>^ i T.)
begin/ end (IMap<K,V>.
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Magazyny wewnętrzneIIterator<T>^ i T.)
begin/ end (Windows::Foundation::Collections::IMapView)

Zdarzenia zmiany kolekcji

Vector obsługa Map powiązania danych w kolekcjach XAML przez zaimplementowanie zdarzeń występujących po zmianie lub zresetowaniu obiektu kolekcji albo wstawienie, usunięcie lub zmianę dowolnego elementu kolekcji. Możesz napisać własne typy, które obsługują powiązanie danych, chociaż nie można dziedziczyć z Map lub Vector dlatego, że te typy są zapieczętowane.

Delegaty windows::Foundation::Collections::VectorChangedEventHandler i Windows::Foundation::Collections::MapChangedEventHandler określają podpisy procedur obsługi zdarzeń dla zdarzeń dotyczących zdarzeń zmiany. Klasy wyliczenia publicznego Windows::Foundation::Collections::CollectionChange oraz Platform::Collection::Details::MapChangedEventArgsPlatform::Collections::Details::VectorChangedEventArgs klasy ref przechowują argumenty zdarzeń, aby określić przyczynę zdarzenia. Typy *EventArgs są definiowane w Details przestrzeni nazw, ponieważ nie trzeba ich konstruować ani używać jawnie podczas korzystania z programu Map lub Vector.

Zobacz też

System typów
Dokumentacja języka C++/CX
Dokumentacja przestrzeni nazw