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 di C più albero di ereditarietà C X per i tipi di raccolta.

Utilizzo dei vettori

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.

Importante

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. Le funzioni begin e end derivano qui dallo spazio dei nomi Platform::Collections , non dallo spazio dei nomi 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();
}

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 Platform::Collections::Vector deve supportare il confronto di uguaglianza, in modo implicito o tramite un criterio di confronto std::equal_to personalizzato specificato. Tutti i tipi di riferimento e tutti i tipi scalari supportano in modo implicito i confronti di uguaglianza. Per i tipi valore non scalari come Windows::Foundation::DateTimeo 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 consentono l'uso di range for cicli e algoritmi come std::sort con un contenitore IVector<T>. Tuttavia, gli elementi IVector non sono accessibili attraverso la dereferenziazione del puntatore C++, ma solo attraverso i metodi GetAt e SetAt . Pertanto, questi iteratori usano le classi proxy e Platform::Details::ArrowProxy<T> per fornire l'accesso ai singoli elementi tramite *gli operatori , ->e [] come richiesto dalla libreria Platform::Details::VectorProxy<T> 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 VectoryProxy 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 Controllo immediato mostra che la variabile iteratore p è di fatto VectorProxy<Person^> con le variabili membro m_v e m_i . Tuttavia, quando chiami GetType su questa variabile, restituisce il tipo identico all'istanza Person di p2. Il vantaggio è che sebbene VectorProxy e ArrowProxy possano apparire in Controllo immediato, il debugger individua alcuni errori del compilatore per cui non in genere necessario scrivere codice.

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, è necessario eseguire il cast dell'elemento su Platform::Objecte 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 del mapping

Questo esempio mostra come inserire gli elementi e come cercarli in Platform::Collections::Map, quindi come restituire l'oggetto Map come tipo Windows::Foundation::Collections::IMapView di sola lettura.

//#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 si deve passare il contenitore attraverso l'interfaccia ABI (Application Binary Interface), costruire un elemento 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 Platform::Collections::Map vengono ordinati. Qualsiasi elemento da archiviare in Map deve supportare l'ordinamento di tipo "strict weak", in modo implicito o tramite un criterio di confronto stl::less personalizzato specificato. 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.

Gli elementi di una raccolta modificabile possono essere modificati, mentre gli elementi di una raccolta di sola lettura, nota come visualizzazione, possono solo essere letti. È possibile accedere agli elementi di un insieme Platform::Collections::VectorView usando un iteratore o l'oggetto Vector::GetAt dell'insieme e un indice. È possibile accedere agli elementi di una raccolta associativa usando map::lookup della raccolta e una chiave.

Classe Platform::Collections::Map
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 oggetto Vector<Windows::Foundation::D ateTime>, è necessario fornire un confronto personalizzato perché DateTime non esegue l'overload dell'operatore ==.

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

Classe Platform::Collections::Vector
Raccolta di sequenze modificabile. Vector<T> supporta operazioni Append di accesso continuo casuale e accesso continuo ammortizzato.

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

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

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

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

Funzioni begin() ed end()

Per semplificare l'uso di STL per elaborare Vectoroggetti arbitrari , VectorView, MapMapView, e Windows::Foundation::Collections , C++/CX supporta gli overload delle funzioni begin Function e end di funzioni non membro.

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

Iteratori Funzioni
Platform::Collections::VectorIterator<T>

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

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

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

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

(Archivi interniIIterator<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 delegati Windows::Foundation::Collections::VectorChangedEventHandler e Windows::Foundation::Collections::MapChangedEventHandler specificano le firme per i gestori eventi per gli eventi di modifica delle raccolte. La classe di enumerazione pubblica Windows::Foundation::Collections::CollectionChange e le classi di riferimento Platform::Collection::Details::MapChangedEventArgs e Platform::Collections::Details::VectorChangedEventArgs archiviano gli argomenti degli eventi per determinare la causa degli eventi. 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.

Vedi anche

Sistema di tipi
Riferimenti al linguaggio C++/CX
Riferimenti a spazi dei nomi