Megosztás:


Gyűjtemények (C++/CX)

A C++/CX programokban ingyenesen használhatja a Standard Sablontár (STL) tárolókat vagy bármely más felhasználó által definiált gyűjteménytípust. Ha azonban a gyűjteményeket oda-vissza továbbítja a Windows futtatókörnyezeti alkalmazás bináris interfészén (ABI) keresztül – például egy XAML-vezérlőnek vagy egy JavaScript-ügyfélnek –, windowsos futtatókörnyezet-gyűjteménytípusokat kell használnia.

A Windows futtatókörnyezet határozza meg a gyűjtemények és a kapcsolódó típusok felületeit, a C++/CX pedig a collection.h fejlécfájlban található konkrét C++ implementációkat biztosítja. Ez az ábra a gyűjteménytípusok közötti kapcsolatokat mutatja be:

A gyűjteménytípusok C és C X öröklési fájának diagramja.

Vektorhasználat

Ha az osztálynak át kell adnia egy szekvenciatárolót egy másik Windows Futtatókörnyezet-összetevőnek, használja Windows::Foundation::Collections::IVector<T> paraméterként vagy visszatérési típusként, valamint Platform::Collections::Vector<T> konkrét megvalósításként. Ha egy nyilvános visszatérési értékben vagy paraméterben Vector típust próbál használni, C3986-os fordítóhiba lép fel. A hiba kijavításához módosítsa a Vector-t egy IVector-re.

Important

Ha a saját programon belül ad át egy sorozatot, akkor használja Vector vagy std::vector, mert hatékonyabbak, mint IVector. Csak akkor használja a IVector-t, ha egy tárolót átvisz az ABI-n.

A Windows futtatókörnyezet típusú rendszer nem támogatja a szaggatott tömbök fogalmát, ezért nem adhat át IVector<Platform::Array<T>> visszatérési értékként vagy metódusparaméterként. Ha át szeretne adni egy szaggatott tömböt vagy sorozatsorozatot az ABI-n, használja a IVector<IVector<T>^>.

Vector<T> biztosítja a gyűjtemény elemeinek hozzáadásához, eltávolításához és eléréséhez szükséges metódusokat, és implicit módon átalakítható IVector<T>. STL-algoritmusokat is használhat a Vector<T>példányain. Az alábbi példa néhány alapszintű használatot mutat be. A begin függvény és end a függvény itt a Platform::Collections névtérből származik, nem a std névtérből.

#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();
}

Ha már rendelkezik olyan kóddal, amely std::vector használ, és egy Windows futtatókörnyezeti összetevőben szeretné újra felhasználni, használja az egyik Vector konstruktort, amely egy std::vector vagy egy iterátorpárot használ egy Vector létrehozására azon a ponton, ahol a gyűjteményt az ABI-n keresztül továbbítja. Az alábbi példa bemutatja, hogyan használható a Vector mozgató konstruktor egy std::vectorhatékony inicializálásához. Az áthelyezési művelet után az eredeti vec változó már nem érvényes.

//#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));
}

Ha van egy sztringek vektora, amelyet egy későbbi időpontban át kell adni az ABI-n keresztül, el kell döntenie, hogy a sztringeket eleve std::wstring vagy Platform::String^ típusként hozza-e létre. Ha sok feldolgozást kell végeznie a karakterláncokon, használja a wstring. Ellenkező esetben hozza létre a karakterláncokat Platform::String^ típusként, és kerülje a későbbi átalakítás költségét. Azt is el kell döntenie, hogy ezeket a karakterláncokat belsőleg egy std::vector vagy Platform::Collections::Vector-ba helyezi-e el. Általános gyakorlatként használja a(z) std::vector-t, és csak akkor hozzon létre belőle egy Platform::Vector-et, amikor a tárolót átengedi az ABI felületén.

Értéktípusok a Vektorban

A tárolt Platform::Collections::Vector elemeknek implicit módon vagy egy ön által megadott egyéni std::equal_to összehasonlító használatával támogatniuk kell az egyenlőségi összehasonlítást. Minden referenciatípus és minden skaláris típus implicit módon támogatja az egyenlőség összehasonlítását. Nem skaláris értéktípusok, például Windows::Foundation::DateTimeegyéni összehasonlítások esetén – például objA->UniqueID == objB->UniqueID– meg kell adnia egy egyéni függvényobjektumot.

VectorProxy-elemek

Platform::Collections::VectorIterator és Platform::Collections::VectorViewIterator lehetővé teszi a range for hurkok és olyan algoritmusok használatát, mint a std::sort egy IVector<T> tárolóval. Az elemeket azonban IVector nem lehet elérni C++ mutató dereferálásával; csak a GetAt és SetAt metódusokkal érhetők el. Ezért ezek az iterátorok Platform::Details::VectorProxy<T> és Platform::Details::ArrowProxy<T> proxy osztályokat használják, hogy az egyes elemekhez hozzáférést biztosítsanak *, -> és [] operátorokon keresztül, ahogy azt a Standard Library megköveteli. Szigorúan véve, ha adott egy IVector<Person^> vec, akkor a *begin(vec) típusa VectorProxy<Person^>. A proxyobjektum azonban szinte mindig átlátható a kód számára. Ezek a proxyobjektumok nincsenek dokumentálva, mert csak belső használatra szolgálnak az iterátorok, de hasznos tudni, hogyan működik a mechanizmus.

Ha tartományalapú for hurkot használ IVector tárolókon keresztül, az auto&& lehetővé teszi, hogy az iterátor változó megfelelően kössön a VectorProxy elemekhez. Ha használja auto&, a C4239 fordító figyelmeztetése megjelenik, és VectorProxy szerepel a figyelmeztető szövegben.

Az alábbi ábrán egy range for hurok látható egy IVector<Person^>felett. Figyelje meg, hogy a végrehajtás leállt a 64. sor töréspontján. A QuickWatch ablak azt mutatja, hogy az iterátor változó p valójában egy VectorProxy<Person^>, amelynek van m_v és m_i tagváltozói. Amikor azonban meghívja a GetType ezen a változón, az visszaadja a Person példány p2azonos típusát. A tanulság az, hogy bár VectorProxy és ArrowProxy megjelenhet a Gyorstárban, a hibakeresőben bizonyos fordítói hibák kapcsán vagy más helyeken, általában nincs szükség arra, hogy kifejezetten kódoljunk rájuk.

Képernyőkép a VectorProxy hibakereséséről egy ciklusalapú tartományban.

Az egyik forgatókönyv, amikor a proxyobjektum körül kell kódolnia, az az, amikor egy dynamic_cast kell végrehajtania az elemeken– például amikor egy adott típusú XAML-objektumot keres egy UIElement elemgyűjteményben. Ebben az esetben először az elemet Platform::Object típusra kell konvertálni, majd végre kell hajtani a dinamikus típuskonverziót.

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...
        }
    }
}

Térkép használata

Ez a példa bemutatja, hogyan szúrhat be elemeket, és hogyan keresheti meg őket egy Platform::Collections::Map-ben, majd adja vissza őket csak olvasható Map típusként.

//#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();
   
}

A belső térképfunkciók esetében általában a std::map típust részesítse előnyben teljesítménybeli okokból. Ha át kell adnia a tárolót az ABI-n keresztül, hozzon létre egy Platform::Collections::Map a std::map-ből, és adja vissza Map-t Windows::Foundation::Collections::IMap formájában. Ha egy nyilvános visszatérési értékben vagy paraméterben Map típust próbál használni, C3986-os fordítóhiba lép fel. A hiba kijavításához módosítsa a Map-t egy IMap-re. Bizonyos esetekben – például ha nem végez nagy számú keresést vagy beszúrást, és gyakran továbbítja a gyűjteményt az ABI-n keresztül –, előfordulhat, hogy az elejétől kezdve kevésbé költséges Platform::Collections::Map használni, és elkerülni a std::mapkonvertálásának költségeit. Mindenesetre kerülje a keresési és beszúrási műveleteket egy IMap-on, mivel a három típus közül ezek a legrosszabb teljesítményűek. Csak akkor konvertáljon IMap-ra, amikor a tárolót az ABI-n keresztül adja át.

Értéktípusok a Térképben

Az elemek Platform::Collections::Map rendezetten vannak. Minden olyan elemnek, amelyet egy Map adott helyen kell tárolni, támogatnia kell a szigorú gyenge rendezésnél kisebb összehasonlítást, akár implicit módon, akár egy ön által megadott egyéni std::less összehasonlító használatával. A skaláris típusok implicit módon támogatják az összehasonlítást. Nem skaláris értéktípusokhoz, például Windows::Foundation::DateTimevagy egyéni összehasonlításokhoz – például objA->UniqueID < objB->UniqueID– egyéni összehasonlítót kell megadnia.

Gyűjteménytípusok

A gyűjtemények négy kategóriába sorolhatók: a sorozatgyűjtemények és az asszociatív gyűjtemények módosítható és csak olvasható verziói. A C++/CX emellett három olyan iterátorosztály biztosításával javítja a gyűjteményeket, amelyek leegyszerűsítik a gyűjtemények elérését.

A módosítható gyűjtemény elemei módosíthatók, de a csak olvasható gyűjtemények elemei, amelyeket nézetnek neveznek, csak olvashatók. Egy Platform::Collections::Vector vagy Platform::Collections::VectorView gyűjtemény elemei egy iterátor, a gyűjtemény Vector::GetAt vagy egy index használatával érhetők el. Az asszociatív gyűjtemény elemei a gyűjtemény Map::Lookup és egy kulcs használatával érhetők el.

Platform::Collections::Map osztály
Módosítható, asszociatív gyűjtemény. A térképelemek kulcs-érték párok. A kulcsok keresése a társított érték lekéréséhez és az összes kulcs-érték páron keresztüli iteráláshoz egyaránt támogatott.

Map és MapView a <K, V, C = std::less<K>>-n alapulnak, így testre szabhatja az összehasonlítási módszert. Emellett a Vector és a VectorView a <T, E = std::equal_to<T>> sablonra alapulnak, így testre szabhatja a IndexOf()viselkedését. Ez elsősorban az értékstruktúra Vector és VectorView szempontjából fontos. Például egy Vector<Windows::Foundation::DateTime> létrehozásához egyéni összehasonlítót kell megadnia, mert a DateTime nem támogatja a == operátor túlterhelését.

Platform::Collections::MapView osztály
Egy Mapírásvédett verziója.

Platform::Collections::Vector osztály
Módosítható sorozatgyűjtemény. Vector<T> támogatja az állandó idejű véletlenszerű hozzáférést és az amortizált-állandó-idő Append műveleteket.

Platform::Collections::VectorView osztály
Egy Vectorírásvédett verziója.

Platform::Collections::InputIterator osztály
StL iterátor, amely megfelel az STL bemeneti iterátor követelményeinek.

Platform::Collections::VectorIterator osztály
Egy STL iterátor, amely megfelel egy STL-mutable véletlenszerű hozzáférésű iterátor követelményeinek.

Platform::Collections::VectorViewIterator osztály
StL iterátor, amely megfelel az STL const véletlenszerű hozzáférésű iterátor követelményeinek.

begin() és end() függvények

Az STL használatának megkönnyítése érdekében C++/CX támogatja a VectorView és MapViewWindows::Foundation::Collections, begin, , end és tetszőleges end objektumok feldolgozására.

Az alábbi táblázat az elérhető iterátorokat és függvényeket sorolja fel.

Iterators Functions
Platform::Collections::VectorIterator<T>

(Belsőleg tárolja Windows::Foundation::Collections::IVector<T> és int.)
begin / end(Windows::Foundation::Collections::IVector<T>)
Platform::Collections::VectorViewIterator<T>

(Belső tárolók IVectorView<T>: ^ és int.)
begin / end (IVectorView<T>^)
Platform::Collections::InputIterator<T>

(Belső tárolók IIterator<T>: ^ és T.)
begin / end (IIterable<T>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Belső tárolók IIterator<T>: ^ és T.)
begin / end (IMap<K,V>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Belső tárolók IIterator<T>: ^ és T.)
begin / end (Windows::Foundation::Collections::IMapView)

Gyűjteményváltozási események

Vector és Map támogatja az XAML-gyűjteményekben való adatkötést olyan események implementálásával, amelyek a gyűjteményobjektumok módosításakor vagy alaphelyzetbe állításakor, illetve a gyűjtemény bármely elemének beszúrása, eltávolítása vagy módosításakor fordulnak elő. Az adatkötést támogató saját típusokat írhat, de nem örökölhet Map vagy Vector, mert ezek a típusok lezárva vannak.

A Windows::Foundation::Collections::VectorChangedEventHandler és Windows::Foundation::Collections::MapChangedEventHandler delegáltak határozzák meg a gyűjteményváltozási eseményekhez tartozó eseménykezelők aláírásait. A Windows::Foundation::Collections::CollectionChange nyilvános enumerálási osztály és Platform::Collections::Details::MapChangedEventArgsPlatform::Collections::Details::VectorChangedEventArgs a ref osztály tárolja az eseményargumentumokat annak meghatározásához, hogy mi okozta az eseményt. A *EventArgs típusok a Details névtérben vannak definiálva, mert nem kell explicit módon létrehoznia vagy felhasználnia őket Map vagy Vectorhasználatakor.

Lásd még

Típus rendszer
C++/CX nyelvi referencia
Névterek – referencia