Compartilhar via


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:

Diagrama da árvore de herança C mais C X para tipos de coleção.

Uso de vetor

Quando sua classe precisar passar um contêiner de sequência para outro componente do Windows Runtime, use Windows::Foundation::Collections::IVector<T> como o 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.

Important

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. A função begin e a função 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 dar suporte à comparação de igualdade, 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 tipos de valor não escalar, como Windows::Foundation::DateTime, ou para comparações personalizadas, por exemplo, objA->UniqueID == objB->UniqueIDvocê deve fornecer um objeto de função personalizado.

Elementos VectorProxy

Platform::Collections::VectorIterator e Platform::Collections::VectorViewIterator habilitam o uso de loops range for e algoritmos como std::sort com um container IVector<T>. Mas os elementos IVector não podem ser acessados por meio da desreferência do ponteiro C++; eles só podem ser acessados por meio dos métodos GetAt e SetAt. Portanto, esses iteradores usam as classes de proxy Platform::Details::VectorProxy<T> e Platform::Details::ArrowProxy<T> para fornecer acesso aos elementos individuais por meio dos operadores *, ->, e [], como exigido pela Biblioteca Padrão. 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 VectorProxy 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 possui variáveis 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 no QuickWatch, no depurador, em certos erros do compilador ou em outros locais, você normalmente não precisa codificá-los explicitamente.

Captura de tela da depuração de VectorProxy em um intervalo baseado em loop.

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, primeiro você deve converter o elemento em Platform::Object^ e 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 pesquisá-los em um Platform::Collections::Map, e, em seguida, retornar o 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 você precisar passar o contêiner pela ABI, construa um Platform::Collections::Map a partir do std::map e retorne o 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

Elementos em um Platform::Collections::Map são ordenados. Qualquer elemento a ser armazenado em um Map deve oferecer suporte à comparação menor com uma ordenação estrita fraca, seja implicitamente ou usando um comparador personalizado std::less que você fornecer. 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.

Elementos de uma coleção modificável podem ser alterados, mas elementos de uma coleção somente leitura, que é conhecida como visualização, só podem ser lidos. Elementos de uma Platform::Collections::Vector ou Platform::Collections::VectorView coleção podem ser acessados usando um iterador ou a coleção Vector::GetAt e um índice. Elementos de uma coleção associativa podem ser acessados usando a coleção Map::Lookup e uma chave.

Platform::Collections::Map classe
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 porque DateTime não sobrecarrega o == operador.

Platform::Collections::MapView classe
Uma versão somente leitura de Map.

Platform::Collections::Vector classe
Uma coleção de sequências modificável. Vector<T> dá suporte ao acesso aleatório em tempo constante e a operações em tempo amortizado constante.

Platform::Collections::VectorView classe
Uma versão somente leitura de Vector.

Platform::Collections::InputIterator classe
Um iterador STL que satisfaz os requisitos de um iterador de entrada STL.

Platform::Collections::VectorIterator classe
Um iterador STL que satisfaz os requisitos de um iterador de acesso aleatório mutável STL.

Platform::Collections::VectorViewIterator classe
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 do STL para processar Vector, VectorView, Map, MapView e objetos arbitrários Windows::Foundation::Collections, C++/CX oferece suporte a sobrecargas das funções não-membro begin e end.

A tabela a seguir lista os iteradores e as funções disponíveis.

Iterators Functions
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.

Windows::Foundation::Collections::VectorChangedEventHandler e Windows::Foundation::Collections::MapChangedEventHandler delegados especificam as assinaturas para manipuladores de eventos para eventos de alteração de coleção. A classe de enumeração pública Windows::Foundation::Collections::CollectionChange, e as classes ref Platform::Collections::Details::MapChangedEventArgs e Platform::Collections::Details::VectorChangedEventArgs, armazenam os argumentos do evento para determinar o que causou 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.

Consulte também

Sistema de Tipos
Referência da linguagem C++/CX
Referência de namespaces