Coleções (C++/CX)
Em um programa do C++/CX, você pode usar livremente os contêineres STL (Biblioteca de Modelos Padrão) ou qualquer outro tipo de coleção definida pelo usuário. No entanto, quando você passa coleções de e para a ABI (Interface binária de aplicativo) do Windows Runtime – por exemplo, a um controle XAML ou a um cliente JavaScript – deve usar os tipos de coleção do Windows Runtime.
O Windows Runtime define as interfaces para coleções e tipos relacionados e o C++/CX fornece as implementações C++ concretas no arquivo de cabeçalho collection.h. Esta ilustração mostra as relações entre os tipos de coleção:
A classe Platform::Collections::Vector é semelhante à classe std::vector.
A classe Platform::Collections::Map é semelhante à classe std::map.
Aclasse Platform::Collections::VectorView e a classe Platform::Collections::MapView são versões somente leitura de
Vector
eMap
.Iteradores são definidos no namespace Platform::Collections. Esses iteradores satisfazem os requisitos para iteradores STL e permitem o uso de std::find, std::count_if e outros algoritmos STL em qualquer tipo de interface Windows::Foundation::Collections ou tipo concreto Platform::Collections. Por exemplo, isso significa que você pode iterar uma coleção em um componente do Windows Runtime criado em C# e aplicar um algoritmo STL a ele.
Importante
Os iteradores proxy
VectorIterator
eVectorViewIterator
utilizam os objetos proxyVectoryProxy<T>
eArrowProxy<T>
para permitir o uso com contêineres STL. Para obter mais informações, consulte "Elementos VectorProxy" mais adiante neste artigo.Os tipos de coleção do C++/CX dão suporte às mesmas garantias de acesso thread-safe às quais os contêineres STL dão suporte.
Windows::Foundation::Collections::IObservableVector e Windows::Foundation::Collections::IObservableMap definem eventos que são acionados quando a coleção é alterada de várias maneiras. Com a implementação dessas interfaces, Platform::Collections::Map e Platform::Collections::Vector oferecem suporte à associação de dados com coleções XAML. Por exemplo, se você tiver um
Vector
com dados associados aGrid
, quando você adicionar um item a uma coleção, a alteração será refletida na interface de usuário da grade.
Uso do vetor
Quando a sua classe precisar transmitir um contêiner de sequência para outro componente do Windows Runtime, use Windows::Foundation::Collections:: IVector<T> como parâmetro ou tipo de retorno e Platform::Collections::Vector<T> como a implementação concreta. Se você tentar usar um tipo Vector
em um valor ou parâmetro de retorno público, será gerado o erro do compilador C3986. Você pode corrigir o erro alterando Vector
para IVector
.
Importante
Se você estiver passando uma sequência no seu próprio programa, use Vector
ou std::vector
, pois eles são mais eficientes do que IVector
. Use IVector
somente ao passar o contêiner pela ABI.
O sistema de tipos do Windows Runtime não oferece suporte ao conceito de matrizes denteadas e, portanto, você não pode passar um IVector<Platform::Array<T>>
como um valor de retorno ou parâmetro de método. Para passar uma matriz denteada ou uma sequência de sequências através da ABI, use IVector<IVector<T>^>
.
Vector<T>
fornece os métodos necessários para adição, remoção e acesso a itens na coleção e é implicitamente conversível em IVector<T>
. Você também pode usar algoritmos STL em instâncias de Vector<T>
. O exemplo a seguir demonstra alguns usos básicos. As funções begin e end aqui são do namespace Platform::Collections
, não do 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();
}
Se houver um código existente que use std::vector
e você quiser reutilizá-lo em um componente do Windows Runtime, basta usar um dos construtores Vector
que adota um std::vector
ou um par de iteradores para construir um Vector
no ponto em que você passa a coleção pela ABI. O exemplo a seguir mostra como usar o construtor de movimentação Vector
para inicialização eficiente de um std::vector
. Após a operação de movimentação, a variável de vec
original não será mais válida.
//#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 você tiver um vetor de cadeias de caracteres que deve passar pela ABI em algum ponto futuro, será preciso decidir se as cadeias de caracteres serão criadas inicialmente como tipos de std::wstring
ou como tipos de Platform::String^
. Se for necessário muito processamento nessas cadeias de caracteres, use wstring
. Caso contrário, crie as cadeias de caracteres como tipos de Platform::String^
e evite o custo de convertê-las posteriormente. Você também deve decidir se essas cadeias de caracteres serão colocadas em um std:vector
ou Platform::Collections::Vector
internamente. Como prática geral, use std::vector
e crie um Platform::Vector
a partir dele somente quando passar o contêiner pela ABI.
Tipos de valor no vetor
Qualquer elemento a ser armazenado em um Platform::Collections::Vector deve oferecer suporte à comparação de igualdade, seja implicitamente ou usando um comparador personalizado std::equal_to que você fornece. Todos os tipos de referência e todos os tipos escalares oferecem suporte implicitamente às comparações de igualdade. Para os tipos de valor não escalar, como Windows::Foundation::DateTime, ou para comparações personalizadas (por exemplo, objA->UniqueID == objB->UniqueID
), é necessário fornecer um objeto de função personalizado.
Elementos VectorProxy
Platform::Collections::VectorIterator e Platform::Collections::VectorViewIterator permitem o uso de loops e algoritmos range for
como std::sort com um contêiner IVector<T>. Porém, os elementos IVector
não podem ser acessados por meio do desreferenciamento do ponteiro C++; eles podem ser acessados somente por pelos métodos GetAt e SetAt . Portanto, esses iteradores usam as classes proxy Platform::Details::VectorProxy<T>
e Platform::Details::ArrowProxy<T>
para oferecer acesso aos elementos individuais por meio dos operadores *, -> e [], conforme exigido pelo STL. Estritamente falando, dado um IVector<Person^> vec
, o tipo de *begin(vec)
será VectorProxy<Person^>
. Entretanto, o objeto proxy é quase sempre transparente ao seu código. Esses objetos proxy não estão documentados porque são apenas para uso interno dos iteradores, mas é útil saber como o mecanismo funciona.
Quando você usar um loop for
baseado em intervalo sobre contêineres IVector
, use auto&&
para habilitar a variável de iterador para associar corretamente aos elementos VectorProxy
. Se você usar auto&
, o aviso do compilador C4239 será gerado e VectoryProxy
será mencionado no texto de aviso.
A ilustração a seguir mostra um loop range for
sobre um IVector<Person^>
. Observe que a execução é interrompida no ponto de interrupção na linha 64. A janela QuickWatch mostra que a variável de iterador p
é na verdade um VectorProxy<Person^>
que tem as variáveis de membro m_v
e m_i
. Entretanto, quando você chama GetType
nessa variável, é retornado o tipo idêntico à instância Person
de p2
. A conclusão é que, embora VectorProxy
e ArrowProxy
possam aparecer em QuickWatch, determinados erros do compilador do depurador, ou outros locais, geralmente não precisam ter uma codificação explícita para eles.
Um cenário em que é necessário codificar em torno do objeto proxy é quando você precisa executar um dynamic_cast
nos elementos — por exemplo, quando você está procurando objetos XAML de um determinado tipo em uma coleção de elementos UIElement
. Nesse caso, você deve primeiro converter o elemento em Platform::Object^ e depois executar a conversão dinâmica:
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...
}
}
}
Uso do mapa
Este exemplo mostra como inserir itens e consultá-los em um Platform::Collections::Map, e depois retornar Map
como um tipo Windows::Foundation::Collections::IMapView somente leitura.
//#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();
}
Em geral, para a funcionalidade de mapa interna, prefira o tipo std::map
por motivos de desempenho. Se precisar transmitir o contêiner pela ABI, construa um Platform::Collections::Map a partir de std::map e retorne Map
como um Windows::Foundation::Collections::IMap. Se você tentar usar um tipo Map
em um valor ou parâmetro de retorno público, será gerado o erro do compilador C3986. Você pode corrigir o erro alterando Map
para IMap
. Em alguns casos (por exemplo, se você não estiver fazendo um grande número de pesquisas ou inserções e estiver passando a coleção pela ABI frequentemente), poderá ser menos caro usar Platform::Collections::Map
desde o início e evitar o custo de converter o std::map
. Em qualquer caso, evite as operações de pesquisa e inserção em um IMap
, pois elas são as menos eficazes dos três tipos. Converta em IMap
somente no ponto em que você passa o contêiner pela ABI.
Tipos de valor no mapa
Os elementos de um Platform::Collections::Map são ordenados. Qualquer elemento a ser armazenado em um Map
deve oferecer suporte à comparação de inferioridade com ordenação fraca estrita, seja implicitamente ou usando um comparador personalizado stl::less fornecido por você. Os tipos escalares oferecem suporte à comparação implicitamente. Para os tipos de valor não escalar, como Windows::Foundation::DateTime
, ou para comparações personalizadas (por exemplo, objA->UniqueID < objB->UniqueID
), você deverá fornecer um comparador personalizado.
Tipos de coleção
As coleções se enquadram em quatro categorias: versões modificáveis e somente leitura das coleções de sequência e coleções associativas. Além disso, o C++/CX aprimora as coleções fornecendo três classes de iterador que simplificam o acesso de coleções.
Os elementos de uma coleção modificável podem ser alterados, mas os elementos de uma coleção somente leitura, que é conhecida como exibição, só podem ser lidos. Os elementos de uma coleção Platform::Collections::Vector ou Platform::Collections::VectorView podem ser acessados com o uso de um iterador ou o Vector::GetAt da coleção e um índice. Os elementos de uma coleção associativa podem ser acessados usando Map::Lookup da coleção e uma chave.
Classe Platform::Collections::Map
uma coleção modificável, associativa. Os elementos de mapa são pares chave-valor. Há suporte para as operações de pesquisar uma chave para recuperar seu valor associado e iterar por todos os pares chave-valor.
Map
e MapView
se tornam modelos no <K, V, C = std::less<K>>
; portanto, você pode personalizar o comparador. Além disso, Vector
e VectorView
se tornam modelos no <T, E = std::equal_to<T>>
para que você possa personalizar o comportamento de IndexOf()
. Isso é importante principalmente para Vector
e VectorView
e estruturas de valor. Por exemplo, para criar um Vector<Windows::Foundation::DateTime>, você deve fornecer um comparador personalizado, pois DateTime não sobrecarrega o operador ==.
Classe Platform::Collections::MapView
Uma versão somente leitura de Map
.
Classe Platform::Collections::Vector
Uma coleção de sequências modificável. Vector<T>
oferece suporte a operações Append de acesso aleatório de tempo constante e de tempo constante amortizado.
Classe Platform::Collections::VectorView
Uma versão somente leitura de Vector
.
Classe Platform::Collections::InputIterator
Um iterador STL que satisfaz os requisitos de um iterador de entrada STL.
Classe Platform::Collections::VectorIterator
Um iterador STL que satisfaz os requisitos de um iterador de acesso aleatório mutável STL.
Classe Platform::Collections::VectorViewIterator
Um iterador STL que satisfaz os requisitos de um iterador de acesso aleatório STL const
.
Funções begin() e end()
Para simplificar o uso de STL para processar Vector
, VectorView
, Map
, MapView
e objetos Windows::Foundation::Collections
arbitrários, o C++/CX oferece suporte a sobrecargas de funções não membro begin Function e end Function.
A tabela a seguir lista os iteradores e as funções disponíveis.
Iterators | Funções |
---|---|
Platform::Collections::VectorIterator<T> (Armazena internamente Windows::Foundation::Collections:: IVector<T> e int.) |
begin/ end(Windows::Foundation::Collections:: IVector<T>) |
Platform::Collections::VectorViewIterator<T> (Armazena internamente IVectorView<T>^ e int.) |
begin/ end (IVectorView<T>^) |
Platform::Collections::InputIterator<T> (Armazena internamente IIterator<T>^ e T.) |
begin/ end (IIterable<T>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Armazena internamente IIterator<T>^ e T.) |
begin/ end (IMap<K,V>. |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Armazena internamente IIterator<T>^ e T.) |
begin/ end (Windows::Foundation::Collections::IMapView) |
Eventos de alteração de coleção
Vector
e Map
oferecem suporte à associação de dados em coleções XAML implementando eventos que ocorrem quando um objeto de coleção é alterado ou redefinido, ou quando um elemento de uma coleção é inserido, removido ou alterado. Você pode escrever seus próprios tipos que ofereçam suporte à associação de dados, embora eles não possam ser herdados de Map
nem de Vector
, pois esses tipos são lacrados.
Os delegados Windows::Foundation::Collections::VectorChangedEventHandler e Windows::Foundation::Collections::MapChangedEventHandler especificam as assinaturas dos manipuladores de eventos para eventos de alteração da coleção. A classe enum pública Windows::Foundation::Collections::CollectionChange e as classes ref Platform::Collection::Details::MapChangedEventArgs
e Platform::Collections::Details::VectorChangedEventArgs
armazenam os argumentos de eventos para determinar o que provocou o evento. Os tipos *EventArgs
são definidos no namespace Details
, pois você não precisa construí-los nem consumi-los explicitamente quando usa Map
ou Vector
.
Confira também
Sistema de tipos
Referência da linguagem C++/CX
Referência de namespaces