Auflistungen (C++/CX)

In einem C++/CX-Programm können Sie STL-Container (Standard Template Library, Standardvorlagenbibliothek) oder jeden anderen benutzerdefinierten Auflistungstyp frei verwenden. Wenn Sie jedoch Auflistungen über die Windows-Runtime-Anwendungsbinärdateischnittstelle (ABI) übergeben – beispielsweise an ein XAML-Steuerelement oder einen JavaScript-Client – müssen Sie Windows-Runtime-Auflistungstypen verwenden.

Die Windows-Runtime definiert die Schnittstellen für Auflistungen und verwandte Typen, und C++/CX stellt die konkreten C++-Implementierungen in der Headerdatei „collection.h“ bereit. Diese Abbildung zeigt die Beziehungen zwischen den Auflistungstypen:

Diagramm der C++/CX-Vererbungsstruktur für Auflistungstypen.

Verwendung von Vektoren

Wenn Ihre Klasse einen Sequenzcontainer an eine andere Windows-Runtime-Komponente übergeben muss, verwenden Sie Windows::Foundation::Collections:: IVector<T> als Parameter oder Rückgabetyp und Platform::Collections::Vector<T> als konkrete Implementierung. Wenn Sie versuchen, einen Vector -Typ in einem öffentlichen Rückgabewert oder Parameter zu verwenden, wird der Compilerfehler C3986 ausgelöst. Sie können das Problem beheben, indem Sie den Vector in einen IVectorändern.

Wichtig

Wenn Sie eine Sequenz im eigenen Programm übergeben, verwenden Sie entweder Vector oder std::vector , da sie effizienter als IVectorsind. Verwenden Sie IVector nur, wenn Sie den Container über die ABI übergeben.

Das Windows-Runtime-Typsystem unterstützt nicht das Konzept von verzweigten Arrays. Deshalb können Sie ein IVector<Platform::Array<T>> nicht als Rückgabewert oder Methodenparameter übergeben. Um ein verzweigtes Array oder eine Sequenz von Sequenzen an die ABI zu übergeben, verwenden Sie IVector<IVector<T>^>.

Vector<T> stellt die Methoden bereit, die zum Hinzufügen, Entfernen und das Zugreifen auf Elemente in der Auflistung erforderlich sind, und kann implizit zu IVector<T>konvertiert werden. Sie können STL-Algorithmen auch bei Instanzen von Vector<T>verwenden. Das folgende Beispiel veranschaulicht die grundlegende Verwendung. Die begin function und end function hier stammen vom Namespace Platform::Collections und nicht vom Namespace std .

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

Wenn der vorhandene Code std::vector verwendet und Sie ihn in einer Windows-Runtime-Komponente wiederverwenden möchten, benutzen Sie einfach einen der Vector-Konstruktoren, der einen std::vector oder ein Paar Iteratoren akzeptiert, um einen Vector an dem Punkt zu erstellen, an dem Sie die Auflistung über die ABI übergeben. Im folgenden Beispiel wird gezeigt, wie der Vector -Bewegungskonstruktor zur effizienten Initialisierung von std::vectorverwendet wird. Nach dem Verschiebungsvorgang ist die ursprüngliche vec -Variable nicht mehr gültig.

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

Wenn Sie einen Vektor von Zeichenfolgen haben, die Sie an einem zukünftigen Punkt über die ABI übergeben müssen, müssen Sie entscheiden, ob die Zeichenfolgen zuerst als std::wstring -Typen oder als Platform::String^ -Typen erstellt werden sollen. Wenn die Zeichenfolgen einen hohen Verarbeitungsaufwand erfordern, verwenden Sie wstring. Erstellen Sie andernfalls die Zeichenfolgen als Platform::String^ -Typen, und vermeiden Sie den Aufwand einer späteren Konvertierung. Außerdem müssen Sie festlegen, ob diese Zeichenfolgen intern in einem std:vector oder in einem Platform::Collections::Vector abgelegt werden sollen. Im Allgemeinen sollten Sie std::vector verwenden und nur dann einen Platform::Vector erstellen, wenn Sie den Container über die ABI übergeben.

Werttypen im Vektor

Jedes in Platform::Collections::Vector gespeicherte Element muss einen Übereinstimmungsvergleich unterstützen, und zwar entweder implizit oder mithilfe eines benutzerdefinierten std::equal_to -Vergleichsoperators, den Sie bereitstellen. Alle Verweistypen und alle skalaren Typen unterstützen implizit Übereinstimmungsvergleiche. Für nicht skalare Werttypen wie Windows::Foundation::DateTimeoder für benutzerdefinierte Vergleiche – z. B. objA->UniqueID == objB->UniqueID– müssen Sie ein benutzerdefiniertes Funktionsobjekt bereitstellen.

VectorProxy-Elemente

Platform::Collections::VectorIterator und Platform::Collections::VectorViewIterator ermöglichen die Verwendung von range for Schleifen und Algorithmen wie std::sort mit einem IVector<T>-Container. IVector -Elemente können jedoch nicht über C++-Zeigerdereferenzierungen aufgerufen werden; auf sie kann nur durch die GetAt - und SetAt -Methode zugegriffen werden. Daher verwenden diese Iteratoren die Proxyklassen Platform::Details::VectorProxy<T> und Platform::Details::ArrowProxy<T>, um Zugriff auf die einzelnen Elemente über die Operatoren *, -> und [] zu ermöglichen, wie von Standardbibliothek gefordert. Streng genommen ist bei einer IVector<Person^> vecder Typ von *begin(vec)VectorProxy<Person^>. Allerdings ist das Proxyobjekt fast immer für Ihren Code transparent. Diese Proxyobjekte werden nicht dokumentiert, da sie nur für die interne Verwendung durch Iteratoren bestimmt sind. Es ist jedoch hilfreich zu wissen, wie der Mechanismus funktioniert.

Wenn Sie eine bereichsbezogene for-Schleife über IVector-Container verwenden, verwenden Sie auto&&, damit die Iteratorvariable korrekt an die VectorProxy-Elemente gebunden werden kann. Wenn Sie auto& verwenden, wird die Compilerwarnung C4239 ausgelöst und VectoryProxy wird im Text der Warnung erwähnt.

Die folgende Abbildung zeigt ein Beispiel für eine range for -Schleife über eine IVector<Person^>. Beachten Sie, dass die Ausführung am Haltepunkt in Zeile 64 beendet wird. Im Fenster Schnellüberwachung wird angezeigt, dass die Iteratorvariable p tatsächlich eine VectorProxy<Person^> ist, die die Membervariablen m_v und m_i aufweist. Wenn Sie jedoch GetType für diese Variable aufrufen, gibt sie den identischen Typ zur Instanz Personp2zurück. Die Schlussfolgerung daraus: Obwohl möglicherweise VectorProxy und ArrowProxy in der Schnellüberwachung, in bestimmten Compilerfehlern des Debuggers oder an anderen Stellen angezeigt werden, müssen Sie sie in der Regel nicht explizit codieren.

Screenshot des Debuggens von VectorProxy in einer bereichsbezogenen Schleife.

Ein Szenario, in dem Sie Code um das Proxyobjekt herum schreiben müssen, ist, wenn Sie eine dynamic_cast für die Elemente durchführen müssen, zum Beispiel, wenn Sie nach XAML-Objekte eines bestimmten Typs in einer UIElement -Elementauflistung suchen. In diesem Fall müssen Sie zuerst das Element in Platform::Object^ umwandeln und dann die dynamische Umwandlung ausführen:

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

Verwendung von Zuordnungen

Dieses Beispiel zeigt, wie Elemente eingefügt und in einer Platform::Collections::Mapgesucht werden und wie die Map anschließend als schreibgeschützter Windows::Foundation::Collections::IMapView -Typ zurückgegeben wird.

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

Im Allgemeinen sollten Sie für die interne Zuordnungsfunktionalität aus Leistungsgründen vorzugsweise den Typ std::map verwenden. Wenn Sie den Container über die ABI übergeben müssen, erstellen Sie eine Platform::Collections::Map von der std::map , und geben Sie den Map als eine Windows::Foundation::Collections::IMapzurück. Wenn Sie versuchen, einen Map -Typ in einem öffentlichen Rückgabewert oder Parameter zu verwenden, wird der Compilerfehler C3986 ausgelöst. Sie können das Problem beheben, indem Sie den Map in einen IMapändern. In einigen Fällen, beispielsweise wenn Sie nur wenige Suchen oder Einfügungen ausführen und die Auflistung häufig über die ABI übergeben, ist es möglicherweise weniger Aufwand, gleich Platform::Collections::Map zu verwenden und die Konvertierung von std::mapzu vermeiden. Vermeiden Sie in jedem Fall Such- und Einfügevorgänge bei einer IMap , da diese der am wenigsten leistungsfähige der drei Typen ist. Konvertieren Sie in IMap nur dann, wenn Sie den Container über die ABI übergeben.

Werttypen in der Zuordnung

Elemente in Platform::Collections::Map werden sortiert. Jedes in Map zu speichernde Element muss den Kleiner-als-Vergleich in strenger, schwacher Reihenfolg unterstützen, und zwar entweder implizit oder mithilfe eines benutzerdefinierten stl::less -Vergleichsoperators, den Sie bereitstellen. Skalare Typen unterstützen den Vergleich implizit. Für nicht skalare Werttypen wie Windows::Foundation::DateTimeoder für benutzerdefinierte Vergleiche – z. B. objA->UniqueID < objB->UniqueID– müssen Sie einen benutzerdefinierten Vergleichsoperator bereitstellen.

Auflistungstypen

Auflistungen sind in vier Kategorien unterteilt: änderbare Versionen und schreibgeschützte Versionen von Sequenzauflistungen und assoziativen Auflistungen. Darüber hinaus verbessert C++/CX Auflistungen durch die Bereitstellung von drei Iteratorklassen, die den Zugriff auf Auflistungen vereinfachen.

Elemente einer änderbaren Auflistung können geändert werden, aber Elemente einer schreibgeschützten Auflistung, die als Ansichtbekannt ist, können nur gelesen werden. Auf Elemente einer Platform::Collections::Vector- oderPlatform::Collections::VectorView-Auflistung kann mit einem Iterator oder mit Vector::GetAt der Auflistung und einem Index zugegriffen werden. Auf Elemente einer assoziativen Auflistung kann mit Map::Lookup der Auflistung und einem Schlüssels zugegriffen werden.

Platform::Collections::Map-Klasse
Eine änderbare, assoziative Auflistung. Zuordnungselemente sind Schlüssel-Wert-Paare. Sowohl das Suchen nach einem Schlüssel, um den zugeordneten Wert abzurufen, als auch das Durchlaufen aller Schlüssel-Wert-Paare werden unterstützt.

Map und MapView sind als Vorlagen für <K, V, C = std::less<K>>vorhanden. Daher können Sie den Vergleichsoperator anpassen. Darüber hinaus sind Vector und VectorView auf <T, E = std::equal_to<T>> vorlagenbasiert, damit Sie das Verhalten von IndexOf()anpassen können. Dies ist vor allem für Vector und VectorView von Wertstrukturen wichtig. Um beispielsweise einen Vector<Windows::Foundation::DateTime> zu erstellen, müssen Sie einen benutzerdefinierten Vergleichsoperator bereitstellen, da DateTime den Operator == nicht überlädt.

Platform::Collections::MapView-Klasse
Eine schreibgeschützte Version von Map.

Platform::Collections::Vector-Klasse
Eine änderbare Sequenzauflistung. Vector<T> unterstützt stetige und amortisierte stetige Append -Direktzugriffsvorgänge.

Platform::Collections::VectorView-Klasse
Eine schreibgeschützte Version von Vector.

Platform::Collections::InputIterator-Klasse
Ein STL-Iterator, der die Anforderungen eines STL-Eingabeiterators erfüllt.

Platform::Collections::VectorIterator-Klasse
Ein STL-Iterator, der die Anforderungen eines änderbaren STL-Iterators mit Direktzugriff erfüllt.

Platform::Collections::VectorViewIterator-Klasse
Ein STL-Iterator, der die Anforderungen eines STL-const-Iterators mit Direktzugriff erfüllt.

begin() und end() -Funktionen

Zur vereinfachten Verwendung der STL für die Verarbeitung von Vector, VectorView, Map, MapView und beliebiger Windows::Foundation::Collections-Objekte unterstützt C++/CX Überladungen der Nicht-Memberfunktionen begin Function und end Function.

Die folgende Tabelle zeigt die verfügbaren Iteratoren und Funktionen auf.

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

(Speichert intern Windows::Foundation::Collections:: IVector<T> und int.)
begin/ end(Windows::Foundation::Collections:: IVector<T>)
Platform::Collections::VectorViewIterator<T>

(Speichert intern IVectorView<T>^ und int.)
begin/ end (IVectorView<T>^)
Platform::Collections::InputIterator<T>

(Speichert intern IIterator<T>^ und T.)
begin/ end (IIterable<T>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Speichert intern IIterator<T>^ und T.)
begin/ end (IMap<K,V>.
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(Speichert intern IIterator<T>^ und T.)
begin/ end (Windows::Foundation::Collections::IMapView)

Änderungsereignisse bei Auflistungen

Vector und Map unterstützen Datenbindung in XAML-Auflistungen durch Implementieren von Ereignissen, die auftreten, wenn ein Auflistungsobjekt geändert oder zurückgesetzt wird oder wenn ein Element in einer Auflistung eingefügt, aus dieser entfernt oder geändert wird. Sie können zwar eigene Typen schreiben, die Datenbindung unterstützen, können jedoch nicht von Map oder von Vector erben, da diese Typen versiegelt sind.

Die Delegaten Windows::Foundation::Collections::VectorChangedEventHandler und Windows::Foundation::Collections::MapChangedEventHandler geben die Signaturen für Ereignishandler für Auflistungsänderungsereignisse an. Die öffentlichen Enumerationsklasse Windows::Foundation::Collections::CollectionChange und die Verweisklassen Platform::Collection::Details::MapChangedEventArgs und Platform::Collections::Details::VectorChangedEventArgs speichern die Ereignisargumente, um herauszufinden, wodurch das Ereignis ausgelöst wurde. *EventArgs-Typen werden im Details-Namespace definiert, da Sie sie nicht explizit erstellen oder nutzen müssen, wenn Sie Map oder Vector verwenden.

Siehe auch

Typsystem
C++-/CX-Programmiersprachenreferenz
Referenz zu Namespaces