Коллекции (C++/CX)
В программе C++/CX можно бесплатно использовать контейнеры стандартной библиотеки шаблонов (STL) или любой другой определяемый пользователем тип коллекции. Однако при передаче коллекций между среда выполнения Windows двоичным интерфейсом приложения (ABI), например в элемент управления XAML или клиенту JavaScript, необходимо использовать среда выполнения Windows типы коллекций.
Среда выполнения Windows определяет интерфейсы для коллекций и связанных типов, а C++/CX предоставляет конкретные реализации C++ в файле заголовка collection.h. На этой иллюстрации показаны связи между типами коллекций:
Класс Platform::Collections::Vector похож на класс std::vector.
Класс Platform::Collections::Map похож на класс std::map.
Класс Platform::Collections::VectorView и класс Platform::Collections::MapView являются версиями
Vector
только для чтения иMap
.Итераторы определяются в пространстве имен Platform::Collections. Эти итераторы удовлетворяют требованиям итераторов STL и позволяют использовать алгоритмы std::find, std::count_ifи другие алгоритмы STL в любом типе интерфейса Windows::Foundation::Collections или конкретном типе Platform::Collections . Например, это означает, что можно выполнить итерацию коллекции в компоненте среда выполнения Windows, созданном в C# и применить к нему алгоритм STL.
Внимание
Итераторы прокси-сервера
VectorIterator
иVectorViewIterator
используют прокси-объектыVectoryProxy<T>
иArrowProxy<T>
для включения использования с контейнерами STL. Дополнительные сведения см. в теме "Элементы VectorProxy" далее в этой статье.Типы коллекций C++/CX поддерживают ту же безопасность потоков, что и контейнеры STL.
Windows::Foundation::Collections::IObservableVector и Windows::Foundation::Collections::IObservableMap определяют события, инициируемые при разнообразных изменениях коллекции. Реализуя эти интерфейсы, объекты Platform::Collections::Map и Platform::Collections::Vector поддерживают привязку данных с коллекциями XAML. Например, если имеется объект
Vector
, данные которого связаны сGrid
, то при добавлении данных в коллекцию их изменения отражаются в пользовательском интерфейсе таблицы.
Использование класса Vector
Когда класс должен передать контейнер последовательности другому компоненту среда выполнения Windows, используйте Windows::Foundation::Collections:: IVector<T> в качестве типа параметра или возвращаемого типа, и Platform::Collections::Vector<T> в качестве конкретной реализации. При попытке использования типа Vector
в качестве открытого возвращаемого значения или параметра возникнет ошибка компилятора C3986. Эту ошибку можно исправить, заменив Vector
объектом IVector
.
Внимание
В случае передачи последовательности внутри разрабатываемой программы используйте Vector
или std::vector
, поскольку они более эффективны по сравнению с IVector
. Используйте IVector
только при передаче контейнера с помощью ABI.
Система типов среда выполнения Windows не поддерживает концепцию сорных массивов, поэтому нельзя передать IVector<Platform::Array<T>>
в качестве возвращаемого значения или параметра метода. Для передачи массива массивов или последовательности массивов в ABI используйте IVector<IVector<T>^>
.
КлассVector<T>
предоставляет методы, необходимые для добавления и удаления элементов коллекции и доступа к ним. Его можно неявно преобразовать в класс IVector<T>
. Алгоритмы STL также можно применять к экземплярам Vector<T>
. В следующем примере демонстрируются некоторые простейшие варианты использования. Функция начала и функция окончания , используемые здесь, — из пространства имен Platform::Collections
, а не 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();
}
Если у вас есть существующий код, который используется std::vector
и вы хотите повторно использовать его в компоненте среда выполнения Windows, просто используйте один из Vector
конструкторов, которые принимают std::vector
или пару итераторов, чтобы создать в Vector
точке, где вы передаете коллекцию через ABI. В следующем примере показано использование конструктора класса Vector
для эффективной инициализации из объекта std::vector
. После операции перемещения исходная переменная vec
более не является допустимой.
//#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));
}
Если имеется вектор строк, которые должны будут передаваться через интерфейс ABI, необходимо решить, следует ли изначально создавать строки как типы std::wstring
или как типы Platform::String^
. Если предполагается выполнение большого объема операций с этими строками, используйте тип wstring
. В противном случае создайте строки типа Platform::String^
, чтобы избежать издержек, связанных с их последующим преобразованием. Кроме того, необходимо определить, куда лучше поместить строки для внутреннего использования — в std:vector
или в Platform::Collections::Vector
. В общем случае рекомендуется использовать объект std::vector
и создавать из него Platform::Vector
только при передаче контейнера через интерфейс ABI.
Типы значений в объекте Vector
Любой элемент, который необходимо сохранить в объекте Platform::Collections::Vector , должен поддерживать сравнение на равенство (неявно или с помощью пользовательского алгоритма сравнения std::equal_to ). Все ссылочные типы и все скалярные типы неявно поддерживают сравнение на равенство. Для нескалярных типов значений, таких как Windows::FoundationDateTime, или для пользовательских сравнений (например, objA->UniqueID == objB->UniqueID
) необходимо предоставить специальный объект функции.
Элементы VectorProxy
Platform::Collections::VectorIterator и Platform::Collections::VectorViewIterator позволяют использовать range for
циклы и алгоритмы, такие как std::sort с контейнером IVector<T>. Однако невозможно получить доступ к элементам IVector
через отмену ссылки на указатель C++; доступ к ним можно получить только с использованием методов GetAt и SetAt . Поэтому эти итераторы используют прокси-классы Platform::Details::VectorProxy<T>
и Platform::Details::ArrowProxy<T>
предоставляют доступ к отдельным элементам через *операторы ,>и [] в соответствии с требованиями стандартной библиотеки. Строго говоря, при использовании IVector<Person^> vec
типом *begin(vec)
является VectorProxy<Person^>
. Однако прокси-объект практически всегда прозрачен для кода. Эти прокси-объекты не документируются, поскольку предназначены исключительно для внутреннего пользования итераторами, однако полезно иметь представление о самом механизме работы.
При использовании цикла на основе for
диапазона по IVector
контейнерам используйте auto&&
для правильной привязки переменных итератора к VectorProxy
элементам. При использовании auto&
возникает предупреждение компилятора C4239 и VectoryProxy
упоминается в тексте предупреждения.
На следующем рисунке показан цикл range for
с контейнерами IVector<Person^>
. Обратите внимание, что выполнение прекращается в точке останова на строке 64. В окне Быстрая проверка показано, что переменная итератора p
, по сути, является объектом VectorProxy<Person^>
с переменными-членами m_v
и m_i
. Однако при вызове GetType
для этой переменной она возвращает идентичный тип в экземпляр Person
p2
. Отсюда вывод: несмотря на то что VectorProxy
и ArrowProxy
могут отображаться в разделе Быстрая проверка, отладчик устраняет некоторые ошибки в компиляторе или других местах, для которых, как правило, не нужно явно создавать код.
Один из сценариев, в котором необходимо создать код для прокси-объекта, заключается в следующем: необходимо выполнить операцию dynamic_cast
с элементами, например при поиске объектов XAML определенного типа в коллекции элементов UIElement
. В этом случае необходимо сначала привести элемент к Platform::Object^, а затем выполнить динамическое приведение.
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...
}
}
}
Использование класса Map
В этом примере показано, как вставлять элементы и находить их в объекте Platform::Collections::Map, а затем возвращать объект Map
в качестве доступного только для чтения типа 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();
}
Как правило, для реализации внутренних возможностей сопоставления предпочтительно использовать тип std::map
(из соображений производительности). Если необходимо передать контейнер с помощью интерфейса ABI, создайте объект Platform::Collections::Map из std::map и верните Map
в качестве Windows::Foundation::Collections::IMap. При попытке использования типа Map
в качестве открытого возвращаемого значения или параметра возникнет ошибка компилятора C3986. Эту ошибку можно исправить, заменив Map
объектом IMap
. В некоторых случаях (например, если вы не выполняете большого количества операций поиска или вставки и часто передаете коллекцию через интерфейс ABI) более рационально использовать класс Platform::Collections::Map
с самого начала, не затрачивая ресурсы на преобразование типа объекта std::map
. В любом случае следует избегать операций поиска и вставки в объектах IMap
, поскольку из всех трех типов он обладает самой низкой производительностью. Преобразование в IMap
следует выполнять только в момент передачи контейнера через интерфейс ABI.
Типы значений в объекте Map
Элементы в Platform::Collections::Map упорядочены. Любой элемент, который необходимо сохранить в объекте Map
, должен поддерживать сравнение "меньше" для строгого слабого порядка (неявно или с помощью пользовательского алгоритма сравнения stl::less ). Скалярные типы поддерживают сравнение неявно. Для нескалярных типов значений, таких как Windows::Foundation::DateTime
, или для пользовательских вариантов сравнения (например, objA->UniqueID < objB->UniqueID
) необходимо определять специальный алгоритм сравнения.
Типы коллекций
Коллекции подразделяются на четыре категории: изменяемые и доступные только для чтения версии последовательных и ассоциативных коллекций. Кроме того, C++/CX улучшает коллекции, предоставляя три класса итератора, упрощающие доступ к коллекциям.
Элементы изменяемой коллекции можно изменять, тогда как к элементам коллекции, доступной только для чтения (также называемой представлением), можно обращаться только для чтения. Доступ к элементам коллекции Platform::Collections::Vector илиPlatform::Collections:VectorView можно получить с помощью итератора или объекта Vector::GetAt и индекса коллекции. К элементам ассоциативной коллекции можно обращаться с помощью карты коллекции ::Lookup и ключа.
Класс Platform::Collections::Map
Изменяемая ассоциативная коллекция. Элементы объекта Map представляют собой пары "ключ-значение". Поддерживается как поиск значения по связанному с ним ключу, так и перебор всех пар "ключ-значение".
В классахMap
и MapView
используется шаблон <K, V, C = std::less<K>>
; таким образом, алгоритм сравнения можно изменять. Кроме того, в классах Vector
и VectorView
используется шаблон <T, E = std::equal_to<T>>
, поэтому поведение метода IndexOf()
можно изменять. Это важно в основном для объектов Vector
и VectorView
, содержащих структуры значения. Например, чтобы создать вектор<Windows::Foundation::D ateTime, необходимо предоставить пользовательский средство сравнения, так как DateTime> не перегружает оператор ==.
Класс Platform::Collections::MapView
Версия объекта Map
только для чтения.
Класс Platform::Collections::Vector
Изменяемая коллекция последовательностей. КлассVector<T>
поддерживает операции произвольного доступа, занимающие фиксированное время, и операции добавления , занимающие фиксированное время с поправкой на амортизацию.
Класс Platform::Collections::VectorView
Версия объекта Vector
только для чтения.
Класс Platform::Collections::InputIterator
Итератор STL, отвечающий требованиям итератора ввода STL.
Класс Platform::Collections::VectorIterator
Итератор STL, отвечающий требованиям изменяемого итератора произвольного доступа STL.
Класс Platform::Collections::VectorViewIterator
Итератор STL, удовлетворяющий требованиям итератора случайного доступа STL const
.
Функции begin() и end()
Чтобы упростить использование STL для обработки Vector
, VectorView
Map
и MapView
произвольных Windows::Foundation::Collections
объектов, C++/CX поддерживает перегрузки функций begin Function и end Function, не являющихся членами.
В следующей таблице перечислены все доступные итераторы и функции.
Итераторы | Функции |
---|---|
Платформа::Collections::VectorIterator<T> (Внутренние хранилища Windows::Foundation::Collections:: IVector<T> и int.) |
begin/ end(Windows::Foundation::Collections:: IVector<T>) |
Platform::Collections::VectorViewIterator<T> (Внутренние хранилища IVectorView<T>^ и int.) |
begin/ end (IVectorView<T>^) |
Платформа::Collections::InputIterator<T> (Внутренние хранилища IIterator<T>^ и T.) |
begin/ end (IIterable<T>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Внутренние хранилища IIterator<T>^ и T.) |
begin/ end (IMap<K,V>. |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Внутренние хранилища IIterator<T>^ и T.) |
begin/ end (Windows::Foundation::Collections::IMapView) |
События изменения коллекций
КлассыVector
и Map
поддерживают привязку данных в коллекциях XAML за счет реализации событий, которые возникают при изменении или сбросе объекта коллекции, а также при вставке, удалении или изменении любого элемента коллекции. Можно разрабатывать собственные типы, поддерживающие привязку данных, но нельзя наследовать от типов Map
и Vector
, так как эти типы запечатаны.
Делегаты Windows::Foundation::Collections::VectorChangedEventHandler и Windows::Foundation::Collections::MapChangedEventHandler определяют сигнатуры для обработчиков событий для событий изменения коллекции. Открытый класс перечисления Windows::Foundation::Collections::CollectionChange и ссылочные классы Platform::Collection::Details::MapChangedEventArgs
и Platform::Collections::Details::VectorChangedEventArgs
хранят аргументы события, по которым можно определить его причину. *EventArgs
Типы определяются в Details
пространстве имен, так как вам не нужно создавать или использовать их явным образом при использовании Map
илиVector
.
См. также
Система типов
Справочник по языку C++/CX
Справочник по пространствам имен