Partilhar via


Coleções (C++/CX)

Em um programa C++/CX, você pode usar gratuitamente contêineres STL (Standard Template Library) ou qualquer outro tipo de coleção definido pelo usuário. No entanto, quando você passa coleções de um lado para o outro pela ABI (interface binária do aplicativo) do Tempo de Execução do Windows — por exemplo, para um controle XAML ou para um cliente JavaScript — você deve usar tipos de coleção do Tempo de Execução do Windows.

O Tempo de Execução do Windows define as interfaces para coleções e tipos relacionados, e o C++/CX fornece as implementações concretas do C++ no arquivo de cabeçalho collection.h. Esta ilustração mostra as relações entre os tipos de coleção:

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

Uso de vetores

Quando sua classe tiver que passar um contêiner de sequência para outro componente do Tempo de Execução do Windows, use Windows::Foundation::Collections::IVector<T> como parâmetro ou tipo de retorno e Platform::Collections::Vector<T> como implementação concreta. Se você tentar usar um tipo de Vector em um valor de retorno público ou parâmetro, o erro de compilador C3986 será gerado. Você pode corrigir o erro alterando o Vector para um IVector.

Important

Se você estiver passando uma sequência dentro do seu próprio programa, use Vector ou std::vector porque eles são mais eficientes do que IVector. Use IVector apenas quando passar o container através da ABI.

O sistema do tipo Tempo de Execução do Windows não oferece suporte ao conceito de matrizes irregulares 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 irregular ou uma sequência de sequências pela ABI, use IVector<IVector<T>^>.

Vector<T> fornece os métodos necessários para adicionar, remover e acessar itens na coleção, e é implicitamente conversível para IVector<T>. Você também pode usar algoritmos STL em instâncias de Vector<T>. O exemplo a seguir demonstra algum uso básico. A begin função e a end função provêm do Platform::Collections namespace, não do std namespace.

#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 tiveres um código existente que usa std::vector e quiseres reutilizá-lo num componente Windows Runtime, basta usar um dos construtores Vector que recebe um std::vector ou um par de iteradores para construir um Vector quando passas a coleção pela ABI. O exemplo a seguir mostra como usar o construtor Vector move para inicialização eficiente a partir de um std::vector. Após a operação de movimentação, a variável vec original não é 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 você deve passar através da ABI em algum ponto futuro, você deve decidir se deseja criar as cadeias de caracteres inicialmente como tipos std::wstring ou como tipos Platform::String^. Se tiveres que fazer muito processamento nas cadeias de caracteres, usa wstring. Caso contrário, crie as cadeias de caracteres como tipos Platform::String^ e evite o custo de convertê-las posteriormente. Você também deve decidir se deseja colocar essas cadeias de caracteres em um std::vector ou Platform::Collections::Vector internamente. Como prática geral, utilize std::vector e só crie um Platform::Vector a partir dele ao passar o contentor pelo ABI.

Tipos de valor em Vetor

Qualquer elemento a ser armazenado em um Platform::Collections::Vector deve suportar a 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 suportam implicitamente comparações de igualdade. Para tipos de valores não escalares, como Windows::Foundation::DateTime, ou para comparações personalizadas; por exemplo, objA->UniqueID == objB->UniqueID, deve-se fornecer um objeto de função personalizado.

Elementos VectorProxy

Platform::Collections::VectorIterator e Platform::Collections::VectorViewIterator permitem o uso de range for loops e algoritmos como std::sort com um IVector<T> contentor. Mas os elementos IVector não podem ser acessados através da desreferência de ponteiro C++; eles podem ser acessados apenas através de GetAt e SetAt. Portanto, esses iteradores usam as classes proxy Platform::Details::VectorProxy<T> e Platform::Details::ArrowProxy<T> para fornecer acesso aos elementos individuais por meio dos operadores *, -> e [], conforme exigido pela Biblioteca Padrão. A rigor, dado um IVector<Person^> vec, o tipo de *begin(vec) é VectorProxy<Person^>. No entanto, o objeto proxy é quase sempre transparente para o seu código. Esses objetos proxy não são documentados porque são apenas para uso interno pelos iteradores, mas é útil saber como o mecanismo funciona.

Ao utilizar um ciclo de for baseado em intervalo em contentores IVector, utilize auto&& para permitir que a variável do iterador se associe corretamente aos elementos VectorProxy. Se você usar auto&, o aviso do compilador C4239 é gerado e VectorProxy é mencionado no texto de aviso.

A ilustração a seguir mostra um loop de range for em 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 iterador p é de fato um VectorProxy<Person^> que tem as variáveis membro m_v e m_i. No entanto, quando você chama GetType nessa variável, ela retorna o tipo idêntico para a instância Personp2. A conclusão é que, embora VectorProxy e ArrowProxy possa aparecer no QuickWatch, no depurador, em certos erros do compilador ou em outros lugares, você normalmente não precisa codificar explicitamente para eles.

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

Um cenário em que você precisa codificar em torno do objeto proxy é quando você precisa executar uma dynamic_cast nos elementos — por exemplo, quando você está procurando objetos XAML de um tipo específico em uma coleção de elementos UIElement. Nesse caso, você deve primeiro converter o elemento para Platform::Object^ e, em seguida, executar a transmissã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...
        }
    }
}

Utilização do mapa

Este exemplo mostra como inserir itens e procurá-los em um Platform::Collections::Map, e em seguida, retornar o Map como um tipo de leitura apenas 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();
   
}

Em geral, para a funcionalidade de mapa interno, prefira o tipo std::map por motivos de desempenho. Se você tiver que passar o contêiner através do ABI, construa um Platform::Collections::Map a partir do std::map e devolva o Map como um Windows::Foundation::Collections::IMap. Se você tentar usar um tipo de Map em um valor de retorno público ou parâmetro, o erro de compilador C3986 será gerado. Você pode corrigir o erro alterando o Map para um IMap. Em alguns casos, por exemplo, se não estiveres a fazer um grande número de consultas ou inserções e estiveres a passar a coleção pela ABI com frequência, pode ser menos dispendioso usar o Platform::Collections::Map desde o início e evitar o custo de conversão do std::map. Em qualquer caso, evite realizar operações de pesquisa e inserção em um IMap, porque estas são as menos eficientes dos três tipos. Converta em IMap somente no ponto em que você passa o contêiner pela ABI.

Tipos de valor em mapa

Os elementos num Platform::Collections::Map são ordenados. Qualquer elemento a ser armazenado em um Map deve suportar menos do que a comparação com ordenação fraca estrita, implicitamente ou usando um comparador personalizado std::less que você fornece. Os tipos escalares suportam a comparação implicitamente. Para tipos de valores não escalares, como Windows::Foundation::DateTime, ou para comparações personalizadas, por exemplo, objA->UniqueID < objB->UniqueID, você deve fornecer um comparador personalizado.

Tipos de recolha

As coleções se dividem em quatro categorias: versões modificáveis e versões somente leitura de coleções de sequências e coleções associativas. Além disso, o C++/CX aprimora as coleções fornecendo três classes iteradoras que simplificam o acesso às coleções.

Os elementos de uma coleção modificável podem ser alterados, mas os elementos de uma coleção somente leitura, conhecida como uma vista, só podem ser lidos. Os elementos de uma coleção Platform::Collections::Vector ou Platform::Collections::VectorView podem ser acedidos utilizando um iterador ou o Vector::GetAt da coleção e um índice. Os elementos de uma coleção associativa podem ser acedidos utilizando Map::Lookup da coleção e uma chave.

Platform::Collections::Map Classe
Uma coleção modificável e associativa. Os elementos do mapa são pares chave-valor. A pesquisa de uma chave para recuperar seu valor associado e a iteração através de todos os pares chave-valor são suportadas.

Map e MapView são modeladas em <K, V, C = std::less<K>>; portanto, você pode personalizar o comparador. Além disso, Vector e VectorView são modeladas em <T, E = std::equal_to<T>> para que você possa personalizar o comportamento de IndexOf(). Isso é importante principalmente para Vector e VectorView de 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 um Map.

Platform::Collections::Vector Classe
Uma coleção de sequências modificáveis. Vector<T> suporta acesso aleatório em tempo constante e operações de tempo amortizado constante Append.

Platform::Collections::VectorView Classe
Uma versão somente leitura de um 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 cumpre os requisitos de um iterador mutável de acesso aleatório STL.

Platform::Collections::VectorViewIterator Classe
Um iterador STL que satisfaz os requisitos de um iterador STL const de acesso aleatório.

funções begin() e end()

Para simplificar o uso da STL para processar Vector, VectorView, Map, MapView e objetos arbitrários Windows::Foundation::Collections, o C++/CX suporta sobrecargas das funções Função begin e Função end não-membro.

A tabela a seguir lista os iteradores e 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 em coleções

Vector e Map oferecem suporte à vinculação de dados em coleções XAML implementando eventos que ocorrem quando um objeto de coleção é alterado ou redefinido, ou quando qualquer elemento de uma coleção é inserido, removido ou alterado. Você pode escrever seus próprios tipos que suportam vinculação de dados, embora não possa herdar de Map ou Vector porque esses tipos são selados.

Os delegados Windows::Foundation::Collections::VectorChangedEventHandler e Windows::Foundation::Collections::MapChangedEventHandler especificam as assinaturas para os manipuladores de eventos para os eventos de alteração de coleção. A Windows::Foundation::Collections::CollectionChange classe enum publíca, e as classes Platform::Collections::Details::MapChangedEventArgs e Platform::Collections::Details::VectorChangedEventArgs, armazenam os argumentos do evento para determinar o que causou o evento. Os tipos de *EventArgs são definidos no namespace Details porque você não precisa construí-los ou consumi-los explicitamente quando usa Map ou Vector.

Ver também

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