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:
La classe Platform::Collections::Vector è simile alla classe std::vector.
La classe Platform::Collections::Map è simile alla classe std::map.
La classe Platform::Collections::VectorView e la classe Platform::Collections::MapView sono versioni di sola lettura di
Vector
eMap
.Gli iteratori sono definiti nello spazio dei nomi Platform::Collections. Questi iteratori soddisfano i requisiti per gli iteratori STL e consentono l'uso di std::find, std::count_ife di altri algoritmi STL su qualsiasi tipo di Windows::Foundation::Collections o tipo concreto Platform::Collections . Questo significa, ad esempio, che è possibile scorrere una raccolta in un componente Windows Runtime creato in C# e applicare un algoritmo STL.
Importante
Gli iteratori proxy
VectorIterator
eVectorViewIterator
usano oggetti proxyVectoryProxy<T>
eArrowProxy<T>
per consentire l'uso con i contenitori STL. Per ulteriori informazioni, vedi "Elementi VectorProxy" più avanti in questo articolo.I tipi di raccolta C++/CX supportano la stessa thread safety garantisce che i contenitori STL supportino.
Windows::Foundation::Collections::IObservableVector e Windows::Foundation::Collections::IObservableMap definiscono gli eventi che vengono generati quando la raccolta cambia in vari modi. Grazie all'implementazione di queste interfacce, Platform::Collections::Map e Platform::Collections::Vector supportano l'associazione dati con le raccolte XAML. Se ad esempio disponi di un oggetto
Vector
con associazione dati a un oggettoGrid
, quando aggiungi un elemento a una raccolta, la modifica viene riflessa nell'interfaccia utente della griglia.
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.
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::DateTime
o 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 Vector
oggetti arbitrari , VectorView
, Map
MapView
, 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