Colecciones (C++/CX)
En un programa de C++/CX puedes hacer uso libre de contenedores de la Biblioteca de plantillas estándar (STL) o de cualquier otro tipo de colección definida por el usuario. Sin embargo, cuando pases colecciones en uno u otro sentido a través de la Interfaz binaria de aplicación (ABI) de Windows Runtime (por ejemplo, a un control XAML o a un cliente de JavaScript) debes utilizar los tipos de colección de Windows Runtime.
Windows Runtime define las interfaces para colecciones y tipos relacionados, y C++/CX proporciona las implementaciones de C++ concretas en el archivo de encabezado collection.h. En esta ilustración se muestran las relaciones entre los tipos de colección:
La clase Platform::Collections::Vector es similar a la clase std::vector.
La clase Platform::Collections::Map es similar a la clase std::map.
La clase Platform::Collections::VectorView y la clase Platform::Collections::MapView son versiones de solo lectura de
Vector
yMap
.Los iteradores se definen en el espacio de nombres Platform::Collections. Estos iteradores cumplen los requisitos de los iteradores de STL y permiten el uso de std::find, std::count_ify otros algoritmos de STL en cualquier tipo de interfaz Windows::Foundation::Collections o tipo de Platform::Collections concreto. Por ejemplo, esto significa que puedes recorrer en iteración una colección en un componente de Windows Runtime creado en C# y aplicarle un algoritmo de STL.
Importante
Los iteradores de proxy
VectorIterator
yVectorViewIterator
usan los objetos proxyVectoryProxy<T>
yArrowProxy<T>
para permitir el uso de contenedores de STL. Para obtener más información, consulta “Elementos de VectorProxy” más adelante en este artículo.Los tipos de colección de C++/CX admiten las mismas garantías de seguridad de subprocesos que los contenedores de STL.
Windows::Foundation::Collections::IObservableVector y Windows::Foundation::Collections::IObservableMap definen eventos que se desencadenan cuando la colección cambia de distintas maneras. Al implementar estas interfaces, Platform::Collections::Map y Platform::Collections::Vector permiten enlaces de datos con colecciones de XAML. Por ejemplo, si tienes un objeto
Vector
que está enlazado a datos a un objetoGrid
, cuando agregues un elemento a una colección, el cambio se reflejará en la interfaz de usuario del objeto Grid.
Uso de Vector
Cuando su clase tenga que pasar un contenedor de secuencias a otro componente de Windows Runtime, use Windows::Foundation::Collections:: IVector<T> como parámetro o tipo de valor devuelto, y Platform::Collections::Vector<T> como la implementación concreta. Si intentas usar un tipo Vector
en un valor devuelto o parámetro público, se producirá el error del compilador C3986. Puedes corregir el error cambiando el tipo Vector
a IVector
.
Importante
Si pasas una secuencia dentro de tu propia programa, utiliza Vector
o std::vector
porque son más eficaces que IVector
. Utiliza IVector
solo cuando pases el contenedor a través de la interfaz binaria de aplicación (ABI).
El sistema de tipos de Windows Runtime no admite el concepto de matrices escalonadas y, por consiguiente, no se puede pasar una clase IVector<Platform::Array<T>>
como valor devuelto o parámetro del método. Para pasar una matriz escalonada o un grupo de secuencias a través de la ABI, usa IVector<IVector<T>^>
.
Vector<T>
proporciona los métodos necesarios para agregar, quitar y tener acceso a los elementos de la colección, y se puede convertir implícitamente a IVector<T>
. También puedes utilizar algoritmos de STL en instancias de Vector<T>
. En el siguiente ejemplo se muestra algún uso básico. La función begin y la función end proceden aquí del espacio de nombres Platform::Collections
, no del espacio de nombres 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();
}
Si tienes código existente que utiliza std::vector
y deseas reutilizarlo en un componente de Windows Runtime, solo tienes que usar uno de los constructores Vector
que toma un objeto std::vector
o un par de iteradores para crear un objeto Vector
en el punto donde pasas la colección a través de ABI. En el ejemplo siguiente se muestra la forma de utilizar el constructor de movimiento Vector
para la inicialización eficaz de un objeto std::vector
. Después de la operación de movimiento, la variable vec
original deja de ser 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));
}
Si tienes un vector de cadenas que debes pasar a través de ABI en algún momento futuro, debes decidir si creas las cadenas inicialmente como tipos de std::wstring
o como tipos de Platform::String^
. Si tienes que hacer una gran cantidad de procesamiento en las cadenas, utiliza wstring
. Si no, crea las cadenas como tipos de Platform::String^
y evita el costo de convertirlas más adelante. También debes decidir si estas cadenas se han de colocar en std:vector
o Platform::Collections::Vector
internamente. Como regla general, usa std::vector
y crea después un objeto Platform::Vector
desde él cuando pases el contenedor a través de ABI.
Tipos de valor de Vector
Cualquier elemento que se almacena en un objeto Platform::Collections::Vector debe admitir la comparación de igualdad, ya sea de forma implícita o mediante el comparador std::equal_to personalizado que proporciones. Todos los tipos de referencia y todos los tipos escalares admiten implícitamente comparaciones de igualdad. Para los tipos de valor no escalares como Windows::Foundation::DateTimeo para las comparaciones personalizadas (por ejemplo, objA->UniqueID == objB->UniqueID
) debes proporcionar un objeto de función personalizado.
Elementos de VectorProxy
Platform::Collections::VectorIterator and Platform::Collections::VectorViewIterator permiten el uso de bucles range for
y algoritmos como std::sort con un contenedor IVector<T>. Sin embargo, no se puede acceder a los elementos de IVector
mediante la desreferencia de un puntero de C++; solo se puede acceder a ellos con los métodos GetAt y SetAt . Por tanto, estos iteradores utilizan las clases de proxy Platform::Details::VectorProxy<T>
y Platform::Details::ArrowProxy<T>
para proporcionar acceso a los distintos elementos con los operadores *, -> y [] tal como STL requiere. En realidad, dado un IVector<Person^> vec
, el tipo de *begin(vec)
es VectorProxy<Person^>
. Sin embargo, el objeto proxy casi siempre es transparente en el código. Estos objetos proxy no están documentados porque solo los usan internamente los operadores, pero es útil conocer cómo funciona el mecanismo.
Cuando usas un bucle for
basado en alcance en contenedores IVector
, utilizas auto&&
para permitir a la variable de iterador enlazar correctamente con los elementos de VectorProxy
. Si usas auto&
, se genera la advertencia del compilador C4239 y se menciona VectoryProxy
en el texto de la advertencia.
En la ilustración siguiente se muestra un bucle range for
en un IVector<Person^>
. Observa que la ejecución se detiene en el punto de interrupción de la línea 64. En la ventana Inspección rápida se muestra que la variable de iterador p
es en realidad un VectorProxy<Person^>
que tiene las variables miembro m_v
y m_i
. Sin embargo, cuando se llama a GetType
en esta variable, se devuelve el tipo idéntico a la instancia Person
de p2
. La clave aquí es que aunque VectorProxy
y ArrowProxy
pueden aparecer en la ventana Inspección rápida, en algunos errores de compilación del depurador o en otros lugares, normalmente no es necesario escribir explícitamente código para ellos.
Un escenario en el que tendrás código alrededor del objeto proxy es cuando tengas que aplicar dynamic_cast
a los elementos (por ejemplo, cuando busques objetos XAML de un tipo determinado en una colección de elementos UIElement
). En este caso, primero debes convertir el elemento en Platform::Object^ y después realizar la conversión 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 de mapa
En este ejemplo se muestra cómo insertar elementos y buscarlos en un objeto Platform::Collections::Mapy devolver después el objeto Map
como un tipo Windows::Foundation::Collections::IMapView de solo lectura.
//#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();
}
Normalmente, para la funcionalidad interna de mapas, es preferible el tipo std::map
por razones de rendimiento. Si tiene que pasar el contenedor a través de la ABI, crea un objeto Platform::Collections::Map desde std::map y devuelve el objeto Map
como un Windows::Foundation::Collections::IMap. Si intentas usar un tipo Map
en un valor devuelto o parámetro público, se producirá el error del compilador C3986. Puedes corregir el error cambiando el tipo Map
a IMap
. En algunos casos (por ejemplo, si no estás realizando un gran número de búsquedas o inserciones y estás pasando la colección a través de ABI con frecuencia), puede ser menos oneroso utilizar Platform::Collections::Map
desde el principio y evitar el costo de convertir el objeto std::map
. En cualquier caso, conviene que evites operaciones de búsqueda e inserción en un objeto IMap
ya que estas son las menos rentables en cuando a rendimiento de los tres tipos. Convierte a IMap
solo en el momento de pasar el contenedor a través de ABI.
Tipos de valor de Map
Los elementos de un objeto Platform::Collections::Map están ordenados. Cualquier elemento que se almacena en Map
debe admitir una comparación de tipo "menor que" con ordenación parcial estricta, ya sea de forma implícita o utilizando el comparador stl::less que proporciones. Los tipos escalares son compatibles con la comparación de forma implícita. Para los tipos de valor no escalares como Windows::Foundation::DateTime
, o para las comparaciones personalizadas (por ejemplo, objA->UniqueID < objB->UniqueID
) debes proporcionar un comparador personalizado.
Tipos de colección
Las colecciones se dividen en cuatro categorías: versiones modificables y versiones de solo lectura de colecciones de secuencia y asociativas. Además, C++/CX mejora las colecciones proporcionando tres clases de iterador que simplifican el acceso de las colecciones.
Los elementos de una colección modificable pueden cambiar, pero los elementos de una colección de solo lectura, que se denomina vista, solo se pueden leer. Se puede acceder a los elementos de Platform::Collections::Vector o Platform::Collections::VectorView con un iterador o Vector::GetAt de la colección, y un índice. Se puede acceder a los elementos de una colección asociativa con Map::Lookup de una colección y una clave.
Platform::Collections::Map (Clase)
Una colección asociativa modificable. Los elementos de mapa son pares clave-valor. Se admiten tanto la búsqueda de una clave para recuperar su valor asociado, como el recorrido en iteración de todos los pares clave-valor.
Map
y MapView
tienen plantillas en <K, V, C = std::less<K>>
; por consiguiente, puedes personalizar el comparador. Además, Vector
y VectorView
tienen plantillas en <T, E = std::equal_to<T>>
, por lo que puedes personalizar el comportamiento de IndexOf()
. Esto es importante principalmente para Vector
y VectorView
de los structs de valor. Por ejemplo, para crear un vector <Windows::Foundation::DateTime>, debe proporcionar un comparador personalizado porque DateTime no sobrecarga el operador ==.
Platform::Collections::MapView (Clase)
Una versión de solo lectura de Map
.
Platform::Collections::Vector (Clase)
Una colección de secuencias modificable. Vector<T>
admite operaciones Append de acceso aleatorio de tiempo constante y de tiempo constante amortizado.
Platform::Collections::VectorView (Clase)
Una versión de solo lectura de Vector
.
Platform::Collections::InputIterator (Clase)
Un iterador de STL que satisface los requisitos de un iterador de entrada de STL.
Platform::Collections::VectorIterator (Clase)
Un iterador de STL que satisface los requisitos de un iterador de acceso aleatorio mutable de STL.
Platform::Collections::VectorViewIterator (Clase)
Un iterador de STL que satisface los requisitos de un iterador de acceso aleatorio const
de STL.
Funciones begin() y end()
Para simplificar el uso del STL para procesar Vector
, VectorView
, Map
MapView
, y objetos arbitrariosWindows::Foundation::Collections
, C++/CX admite sobrecargas de las funciones begin Function y end Function que no son miembro.
En la tabla siguiente se enumeran los iteradores y las funciones disponibles.
Iteradores | Funciones |
---|---|
Platform::Collections::VectorIterator<T> (Almacena internamente Windows::Foundation::Collections:: IVector<T> e int). |
begin/ end(Windows::Foundation::Collections:: IVector<T>) |
Platform::Collections::VectorViewIterator<T> (Almacena internamente IVectorView<T>^ e int). |
begin/ end (IVectorView<T>^) |
Platform::Collections::InputIterator<T> (Almacena internamente IIterator<T>^ y T). |
begin/ end (IIterable<T>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Almacena internamente IIterator<T>^ y T). |
begin/ end (IMap<K,V>. |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Almacena internamente IIterator<T>^ y T). |
begin/ end (Windows::Foundation::Collections::IMapView) |
Eventos de cambios en colecciones
Vector
y Map
admiten el enlace de datos en colecciones de XAML mediante la implementación de eventos que se producen cuando se cambia o se restablece un objeto de colección, o cuando se inserta, se quita o se cambia cualquier elemento de una colección. Puedes escribir tus propios tipos que admitan enlace de datos, aunque no puedes heredar de Map
o Vector
porque esos tipos están sellados.
Los delegados Windows::Foundation::Collections::VectorChangedEventHandler y Windows::Foundation::Collections::MapChangedEventHandler especifican las firmas de los controladores de eventos para los eventos de cambio de la colección. La clase de enumeración pública Windows::Foundation::Collections::CollectionChange y las clases ref Platform::Collection::Details::MapChangedEventArgs
y Platform::Collections::Details::VectorChangedEventArgs
almacenan los argumentos de eventos para determinar la causa del evento. Los tipos *EventArgs
se definen en el espacio de nombres Details
porque no tienes que crearlos ni usarlos de forma explícita cuando utilices Map
o Vector
.
Consulte también
Sistema de tipos
Referencia del lenguaje C++/CX
Referencia de espacios de nombres