Condividi tramite


Raccolte (C++/CX)

In un programma C++/CX è possibile usare gratuitamente i contenitori STL (Standard Template Library) o qualsiasi altro tipo di raccolta definito dall'utente. Tuttavia, quando passi le raccolte all'interno dell'interfaccia ABI (Application Binary Interface) di Windows Runtime, ad esempio a un controllo XAML o a un client JavaScript, devi usare i tipi di raccolta di Windows Runtime.

Windows Runtime definisce le interfacce per le raccolte e i tipi correlati e C++/CX fornisce le implementazioni C++ concrete nel file di intestazione collection.h. Nella seguente immagine vengono mostrate le relazioni tra i tipi di raccolta:

Diagramma dell'albero di ereditarietà C++ C X per i tipi di raccolta.

Utilizzo del vettore

Quando la classe deve passare un contenitore di sequenze a un altro componente Windows Runtime, usare Windows::Foundation::Collections::IVector<T> come parametro o tipo restituito e Platform::Collections::Vector<T> come implementazione concreta. Se tenti di usare un tipo Vector in un parametro o in un valore restituito pubblico, viene generato l'errore del compilatore C3986. Puoi correggere l'errore modificando l'oggetto Vector in un oggetto IVector.

Important

Se passi una sequenza nel tuo programma, utilizza Vector o std::vector perché sono più efficienti rispetto a IVector. Utilizza IVector solo quando passi il contenitore nell'ABI.

Il sistema di tipi Windows Runtime non supporta il concetto di matrici irregolari e pertanto non è possibile passare come IVector<Platform::Array<T>> valore restituito o parametro del metodo. Per passare una matrice di matrici o una sequenza di sequenze attraverso l'interfaccia applicativa binaria (ABI), usa IVector<IVector<T>^>.

Vector<T> fornisce i metodi necessari per l'aggiunta, la rimozione e l'accesso agli elementi nella raccolta ed è implicitamente convertibile in IVector<T>. Puoi anche utilizzare gli algoritmi STL nelle istanze di Vector<T>. Nell'esempio riportato di seguito viene illustrato l'utilizzo di base. La funzione begin e end qui provengono dallo Platform::Collections spazio dei nomi, non dallo std spazio dei nomi.

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

Se hai codice esistente che usa std::vector e vuoi riutilizzarlo in un componente Windows Runtime, usa solo uno dei Vector costruttori che accetta una std::vector o una coppia di iteratori per costruire un Vector oggetto nel punto in cui passi la raccolta nell'ABI. Nell'esempio seguente viene illustrato come utilizzare il costruttore di spostamento Vector per ottenere un'inizializzazione efficiente da un oggetto std::vector. Dopo l'operazione di spostamento, la variabile vec originale non è più valida.

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

Se disponi di un vettore di stringhe da passare attraverso l'ABI in un dato momento futuro, devi decidere se creare le stringhe inizialmente come tipi std::wstring o come tipi Platform::String^ . Se sono richieste numerose attività di elaborazione sulle stringhe, utilizza wstring. Altrimenti, crea le stringhe come tipi Platform::String^ per evitare di doverle convertire in seguito. Devi inoltre decidere se inserire queste stringhe in un oggetto std::vector o Platform::Collections::Vector internamente. Come regola generale, utilizza std::vector e quindi crea da esso un oggetto Platform::Vector solo quando passi il contenitore nell'ABI.

Tipi di valore in Vector

Qualsiasi elemento da archiviare in un Platform::Collections::Vector deve supportare il confronto di uguaglianza, in modo implicito o tramite un comparatore personalizzato std::equal_to fornito dall'utente. Tutti i tipi di riferimento e tutti i tipi scalari supportano in modo implicito i confronti di uguaglianza. Per i tipi valore non scalari, Windows::Foundation::DateTimead esempio , o per i confronti personalizzati, ad esempio, objA->UniqueID == objB->UniqueIDè necessario fornire un oggetto funzione personalizzato.

Elementi VectorProxy

Platform::Collections::VectorIterator e Platform::Collections::VectorViewIterator abilitano l'uso di range for cicli e di algoritmi, come std::sort, con un IVector<T> contenitore. Non è tuttavia IVector possibile accedere agli elementi tramite la dereferenziazione del puntatore C++. È possibile accedervi solo tramite i metodi GetAt e SetAt. Pertanto, questi iteratori usano le classi proxy Platform::Details::VectorProxy<T> e Platform::Details::ArrowProxy<T> per fornire l'accesso ai singoli elementi tramite gli operatori *, -> e [], come richiesto dalla libreria standard. In linea puramente teorica, dato un elemento IVector<Person^> vec, il tipo di *begin(vec) è VectorProxy<Person^>. L'oggetto proxy, tuttavia, è quasi sempre trasparente al codice utente. Questi oggetti proxy non sono documentati in quanto riservati al solo uso interno da parte degli iteratori, è tuttavia utile conoscere il funzionamento del meccanismo.

Quando si usa un ciclo basato su for intervalli su IVector contenitori, usare auto&& per consentire alla variabile iteratore di eseguire correttamente il VectorProxy binding agli elementi. Se si usa auto&, viene generato l'avviso del compilatore C4239 e VectorProxy viene indicato nel testo dell'avviso.

La figura seguente mostra un ciclo range for su un elemento IVector<Person^>. Come puoi notare, l'esecuzione si interrompe al punto di interruzione sulla linea 64. La finestra di QuickWatch mostra che la variabile iteratore p è di fatto un oggetto VectorProxy<Person^> che ha variabili membro m_v e m_i. Tuttavia, quando chiami GetType su questa variabile, restituisce il tipo identico all'istanza Person di p2. Il punto è che anche se VectorProxy e ArrowProxy potrebbero essere visualizzati in Controllo immediato, nel debugger, certi errori del compilatore, o altri contesti, in genere non è necessario codificarli esplicitamente per loro.

Screenshot del debug di VectorProxy in un ciclo for basato su intervallo.

Uno scenario che richiede la scrittura di codice attorno all'oggetto proxy è quando è necessario eseguire il dynamic_cast sugli elementi, ad esempio quando si cercano oggetti XAML di un determinato tipo in una raccolta di elementi UIElement . In questo caso, è prima necessario eseguire il cast dell'elemento a Platform::Object^ e quindi eseguire il cast dinamico:

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

Utilizzo mappa

In questo esempio viene illustrato come inserire gli elementi e cercarli in un Platform::Collections::Map e quindi restituirli come un tipo Map di sola lettura 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();
   
}

In genere, per la funzionalità interna di mapping, è preferibile il tipo std::map per motivi di prestazioni. Se è necessario trasmettere il contenitore attraverso l'ABI, costruire un Platform::Collections::Map da std::map e restituire Map come Windows::Foundation::Collections::IMap. Se tenti di usare un tipo Map in un parametro o in un valore restituito pubblico, viene generato l'errore del compilatore C3986. Puoi correggere l'errore modificando l'oggetto Map in un oggetto IMap. In alcuni casi, ad esempio quando si fanno poche ricerche o pochi inserimenti e si passa spesso la raccolta tramite l'interfaccia ABI, può essere più conveniente utilizzare Platform::Collections::Map dall'inizio ed evitare di dover convertire std::map. In ogni caso, è bene evitare operazioni di ricerca e di inserimento in un oggetto IMap perché queste offrono prestazioni più scarse tra i tre tipi. Esegui la conversione in IMap solo nel punto in cui passi il contenitore attraverso l'interfaccia ABI.

Tipi di valore in Map

Gli elementi in un Platform::Collections::Map sono ordinati. Qualsiasi elemento da archiviare in un Map deve supportare un confronto minore di con ordinamento debole rigoroso, in modo implicito o tramite un confronto personalizzato std::less fornito dall'utente. I tipi scalari supportano il confronto in modo implicito. Per i tipi di valore non scalari come Windows::Foundation::DateTimeo per i confronti personalizzati, ad esempio objA->UniqueID < objB->UniqueID, devi fornire un criterio di confronto personalizzato.

Tipi di raccolta

Le raccolte sono suddivise in quattro categorie: versioni modificabili e versioni di sola lettura di raccolte di sequenze e raccolte associative. Inoltre, C++/CX migliora le raccolte fornendo tre classi di iteratore che semplificano l'accesso alle raccolte.

È possibile modificare gli elementi di una raccolta modificabile, ma gli elementi di una raccolta di sola lettura, nota come visualizzazione, possono essere letti solo. È possibile accedere agli elementi di una Platform::Collections::Vector collezione o Platform::Collections::VectorView utilizzando un iteratore oppure la collezione Vector::GetAt e un indice. È possibile accedere agli elementi di una raccolta associativa usando la Map::Lookup della raccolta e una chiave.

Platform::Collections::Map classe
Raccolta associativa modificabile. Gli elementi della mappa sono coppie chiave-valore. Sono supportati sia la ricerca della chiave per recuperare il valore associato che lo scorrimento di tutte le coppie chiave-valore.

Map e MapView sono basati su modelli in <K, V, C = std::less<K>>; di conseguenza, è possibile personalizzare il criterio di confronto. Inoltre, Vector e VectorView sono basati su modelli in <T, E = std::equal_to<T>> , pertanto puoi personalizzare il comportamento di IndexOf(). Ciò è importante soprattutto per gli struct di valore di Vector e VectorView . Ad esempio, per creare un Vector<Windows::Foundation::DateTime> oggetto, è necessario fornire un comparator personalizzato perché DateTime non esegue l'overload dell'operatore ==.

Platform::Collections::MapView classe
Versione di sola lettura di un oggetto Map.

Platform::Collections::Vector classe
Raccolta di sequenze modificabile. Vector<T> supporta l'accesso casuale in tempo costante e le operazioni in tempo costante ammortizzato Append.

Platform::Collections::VectorView classe
Versione di sola lettura di un oggetto Vector.

Platform::Collections::InputIterator classe
Iteratore STL che soddisfa le richieste di un iteratore di input STL.

Platform::Collections::VectorIterator classe
Iteratore STL che soddisfa le richieste di un iteratore STL di accesso causale modificabile.

Platform::Collections::VectorViewIterator classe
Iteratore STL che soddisfa i requisiti di un iteratore ad accesso casuale STL const .

Funzioni begin() ed end()

Per semplificare l'uso dello STL per elaborare , , , e oggetti arbitrari , C++/CX supporta gli overload delle funzioni e non membro.

Nella tabella seguente sono elencati gli iteratori e le funzioni disponibili.

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

(Archivia internamente Windows::Foundation::Collections::IVector<T> e int.)
begin / end(Windows::Foundation::Collections::IVector<T>)
Platform::Collections::VectorViewIterator<T>

Archivia internamente IVectorView<T>^ e int.)
begin / end (IVectorView<T>^)
Platform::Collections::InputIterator<T>

Archivia internamente IIterator<T>^ e T.)
begin / end (IIterable<T>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

Archivia internamente IIterator<T>^ e T.)
begin / end (IMap<K,V>)
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

Archivia internamente IIterator<T>^ e T.)
begin / end (Windows::Foundation::Collections::IMapView)

Eventi di modifica della raccolta

Vector e Map supportano l'associazione dati nelle raccolte XAML mediante l'implementazione di eventi causati da modifiche o reimpostazioni di un oggetto Collection e da inserimento, rimozione o modifica di qualsiasi elemento di una raccolta. Puoi creare tipi personalizzati che supportano l'associazione dati, anche se non è possibile ereditare da Map o da Vector perché questi tipi sono sealed.

I Windows::Foundation::Collections::VectorChangedEventHandler delegati e Windows::Foundation::Collections::MapChangedEventHandler specificano le firme per i gestori di eventi per gli eventi di cambiamento della raccolta. Le Windows::Foundation::Collections::CollectionChange classi di enumerazione pubblica e Platform::Collections::Details::MapChangedEventArgsPlatform::Collections::Details::VectorChangedEventArgs ref archiviano gli argomenti dell'evento per determinare la causa dell'evento. I *EventArgs tipi sono definiti nello Details spazio dei nomi perché non è necessario crearli o utilizzarli in modo esplicito quando si usa Map o Vector.

Vedere anche

Sistema dei tipi
Riferimenti al linguaggio C++/CX
Riferimenti ai namespace