Dela via


Samlingar (C++/CX)

I ett C++/CX-program kan du använda STL-containrar (Standard Template Library) kostnadsfritt eller någon annan användardefinierad samlingstyp. Men när du skickar samlingar fram och tillbaka över windows Runtime-programmets binära gränssnitt (ABI) – till exempel till en XAML-kontroll eller till en JavaScript-klient – måste du använda samlingstyper för Windows Runtime.

Windows Runtime definierar gränssnitten för samlingar och relaterade typer, och C++/CX tillhandahåller de konkreta C++-implementeringarna i header-filen collection.h. Den här bilden visar relationerna mellan samlingstyperna:

Diagram över C plus C X arvsträd för samlingstyper.

Vektoranvändning

När klassen måste skicka en sekvenscontainer till en annan Windows Runtime-komponent använder Windows::Foundation::Collections::IVector<T> du som parameter eller returtyp och Platform::Collections::Vector<T> som konkret implementering. Om du försöker använda en Vector typ i ett offentligt returvärde eller en parameter genereras kompilatorfelet C3986. Du kan åtgärda felet genom att ändra Vector till en IVector.

Important

Om du skickar en sekvens i ditt eget program använder du antingen Vector eller std::vector eftersom de är effektivare än IVector. Använd endast IVector när du skickar containern över ABI.

Windows Runtime-typsystemet stöder inte begreppet ojämna matriser och därför kan du inte skicka en IVector<Platform::Array<T>> som ett returvärde eller en metodparameter. Om du vill skicka en ojämn matris eller en sekvens med sekvenser över ABI använder du IVector<IVector<T>^>.

Vector<T> innehåller de metoder som krävs för att lägga till, ta bort och komma åt objekt i samlingen, och det är implicit konvertibelt till IVector<T>. Du kan också använda STL-algoritmer på instanser av Vector<T>. I följande exempel visas viss grundläggande användning. Funktionenbegin och end funktionen här kommer från Platform::Collections namnområdet, inte std namnområdet.

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

Om du har befintlig kod som använder std::vector och du vill återanvända den i en Windows Runtime-komponent använder du bara en av de Vector konstruktorer som tar en std::vector eller ett par iteratorer för att skapa en Vector vid den punkt där du skickar samlingen över ABI. I följande exempel visas hur du använder Vector-flyttkonstruktör för effektiv initiering från en std::vector. Efter flyttåtgärden är den ursprungliga vec variabeln inte längre giltig.

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

Om du har en strängvektor som du måste skicka över ABI vid någon framtida tidpunkt måste du bestämma om du ska skapa strängarna från början som std::wstring typer eller som Platform::String^ typer. Om du behöver bearbeta strängarna mycket använder du wstring. Annars skapar du strängarna som Platform::String^ typer och undviker kostnaden för att konvertera dem senare. Du måste också bestämma om du vill placera dessa strängar internt i en std::vector eller Platform::Collections::Vector. Som allmän praxis använder du std::vector och skapar sedan en Platform::Vector från den bara när du skickar containern över ABI.

Värdetyper i Vector

Alla element som ska lagras i en Platform::Collections::Vector måste ha stöd för likhetsjämförelse, antingen implicit eller med hjälp av en anpassad std::equal_to jämförelse som du anger. Alla referenstyper och alla skalära typer stöder implicit likhetsjämförelser. För icke-skalära värdetyper som Windows::Foundation::DateTime, eller för anpassade jämförelser, till exempel , objA->UniqueID == objB->UniqueIDmåste du ange ett anpassat funktionsobjekt.

VectorProxy-elementen

Platform::Collections::VectorIterator och Platform::Collections::VectorViewIterator aktiverar användningen av range for-loopar och algoritmer som std::sort med en IVector<T>-container. Dock går det inte att komma åt IVector-element via C++-pekaravreferens; de kan endast nås via GetAt och SetAt-metoder. Därför använder dessa iteratorer proxyklasserna Platform::Details::VectorProxy<T> och Platform::Details::ArrowProxy<T> för att ge åtkomst till de enskilda elementen via *, ->och [] operatorer, enligt standardbiblioteket. Strängt taget, givet en IVector<Person^> vec, är typen av *begin(vec)VectorProxy<Person^>. Proxyobjektet är dock nästan alltid transparent för koden. Dessa proxyobjekt dokumenteras inte eftersom de endast är för internt bruk av iteratorerna, men det är användbart att veta hur mekanismen fungerar.

När du använder en intervallbaserad for-loop över IVector containrar använder du auto&& för att aktivera iteratorvariabeln för att binda korrekt till de VectorProxy elementen. Om du använder auto&aktiveras kompilatorvarningen C4239 och VectorProxy anges i varningstexten.

Följande bild visar en range for-loop över en IVector<Person^>. Observera att exekveringen stoppas vid brytpunkten på rad 64. Fönstret QuickWatch visar att iteratorvariabeln p i själva verket är en VectorProxy<Person^> som har m_v och m_i medlemsvariabler. Men när du anropar GetType för den här variabeln returneras den identiska typen till den Person instansen p2. Sammanfattningen är att även om VectorProxy och ArrowProxy kan visas i QuickWatch, vissa kompilatorfel eller andra platser i felsökaren, behöver du vanligtvis inte uttryckligen koda för dem.

Skärmbild av felsökning av VectorProxy i ett intervall baserat på loop.

Ett scenario där du måste koda runt proxyobjektet är när du måste utföra en dynamic_cast på elementen, till exempel när du letar efter XAML-objekt av en viss typ i en UIElement elementsamling. I det här fallet måste du först omvandla elementet till Platform::Object^ och sedan utföra den dynamiska gjutningen:

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

Kartanvändning

Det här exemplet visar hur du infogar objekt och söker upp dem i en Platform::Collections::Map, och sedan returnerar Map som en skrivskyddad Windows::Foundation::Collections::IMapView datatyp.

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

För interna kartfunktioner föredras i allmänhet typen std::map för prestandaskäl. Om du måste skicka containern över ABI skapar du en Platform::Collections::Map från std::map och returnerar Map som en Windows::Foundation::Collections::IMap. Om du försöker använda en Map typ i ett offentligt returvärde eller en parameter genereras kompilatorfelet C3986. Du kan åtgärda felet genom att ändra Map till en IMap. I vissa fall, till exempel om du inte gör ett stort antal sökningar eller infogningar, och du skickar samlingen via ABI ofta, kan det vara billigare att använda Platform::Collections::Map från början och undvika kostnaden för att konvertera std::map. Undvik i vilket fall som helst uppslags- och infogningsåtgärder på en IMap eftersom dessa är minst högpresterande av de tre typerna. Konvertera till IMap endast vid den punkt där du skickar containern över ABI.

Värdetyper i Map

Elementen i en Platform::Collections::Map är ordnade. Alla element som ska lagras i en Map måste ha stöd för mindre än jämförelse med strikt svag ordning, antingen implicit eller med hjälp av en anpassad std::less jämförelse som du anger. Skalära typer stöder jämförelsen implicit. För icke-skalära värdetyper som Windows::Foundation::DateTimeeller för anpassade jämförelser– till exempel objA->UniqueID < objB->UniqueID– måste du ange en anpassad jämförelse.

Samlingstyper

Samlingar delas in i fyra kategorier: ändringsbara versioner och skrivskyddade versioner av sekvenssamlingar och associativa samlingar. Dessutom förbättrar C++/CX samlingar genom att tillhandahålla tre iteratorklasser som förenklar åtkomsten av samlingar.

Element i en ändringsbar samling kan ändras, men element i en skrivskyddad samling, som kallas för en vy, kan bara läsas. Element i en Platform::Collections::Vector eller Platform::Collections::VectorView en samling kan nås med hjälp av en iterator eller samlingens Vector::GetAt och ett index. Element i en associativ samling kan nås med hjälp av samlingens Map::Lookup och en nyckel.

Klassen Platform::Collections::Map
En ändringsbar, associativ samling. Dessa kartelement är nyckel-värde-par. Att leta upp en nyckel för att hämta dess associerade värde och iterera genom alla nyckel/värde-par stöds båda.

Map och MapView mallas på <K, V, C = std::less<K>>; Därför kan du anpassa jämförelsen. Dessutom mallas Vector och VectorView<T, E = std::equal_to<T>> så att du kan anpassa beteendet för IndexOf(). Detta är främst viktigt för Vector och VectorView av värdestrukturer. Om du till exempel vill skapa en Vector<Windows::Foundation::DateTime>måste du ange en anpassad jämförelse eftersom DateTime inte överbelastar operatorn == .

Klassen Platform::Collections::MapView
En skrivskyddad version av en Map.

Klassen Platform::Collections::Vector
En ändringsbar sekvenssamling. Vector<T> stöder slumpmässig åtkomst med konstant tid och åtgärder med amorterad konstant tid Append .

Klassen Platform::Collections::VectorView
En skrivskyddad version av en Vector.

Klassen Platform::Collections::InputIterator
En STL-inmatningsiterator som uppfyller kraven för en STL-inmatningsiterator.

Klassen Platform::Collections::VectorIterator
En STL-iterator som uppfyller kraven för en muterbar random-access-iterator i STL.

Klassen Platform::Collections::VectorViewIterator
En STL-iterator som uppfyller kraven för en STL-const iterator med slumpmässig åtkomst.

funktionerna begin() och end()

För att förenkla användningen av STL för att bearbeta , , , och godtyckliga objekt stöder C++/CX överlagringar av och funktionerna som icke-medlemsfunktioner.

I följande tabell visas tillgängliga iteratorer och funktioner.

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

(Lagrar internt Windows::Foundation::Collections::IVector<T> och int.)
begin / end(Windows::Foundation::Collections::IVector<T>)
Platform::Collections::VectorViewIterator<T>

(Lagrar IVectorView<T>^ och int.) internt
begin / end (IVectorView<T>^)
Platform::Collections::InputIterator<T>

(Lagrar IIterator<T>^ och T.) internt
begin / end (IIterable<T>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Lagrar IIterator<T>^ och T.) internt
begin / end (IMap<K,V>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Lagrar IIterator<T>^ och T.) internt
begin / end (Windows::Foundation::Collections::IMapView)

Ändringshändelser för samling

Vector och Map stöder databindning i XAML-samlingar genom att implementera händelser som inträffar när ett samlingsobjekt ändras eller återställs, eller när något element i en samling infogas, tas bort eller ändras. Du kan skriva egna typer som stöder databindning, även om du inte kan ärva från Map eller Vector eftersom dessa typer är förseglade.

Delegaterna Windows::Foundation::Collections::VectorChangedEventHandler och Windows::Foundation::Collections::MapChangedEventHandler specificerar signaturer för händelsehanterare för samlingsändringshändelser. Den Windows::Foundation::Collections::CollectionChange offentliga enum klassen och Platform::Collections::Details::MapChangedEventArgs och Platform::Collections::Details::VectorChangedEventArgs ref klasserna lagrar händelseargumenten för att avgöra vad som orsakade händelsen. De *EventArgs typerna definieras i namnområdet Details eftersom du inte behöver konstruera eller använda dem explicit när du använder Map eller Vector.

Se även

typsystem
C++/CX-språkreferens
referens för namnområden