Поделиться через


Collections (C++/CX)

В программе C++/CX можно бесплатно использовать контейнеры стандартной библиотеки шаблонов (STL) или любой другой определяемый пользователем тип коллекции. Однако при передаче коллекций между среда выполнения Windows двоичным интерфейсом приложения (ABI), например в элемент управления XAML или клиенту JavaScript, необходимо использовать среда выполнения Windows типы коллекций.

Среда выполнения Windows определяет интерфейсы для коллекций и связанных типов, а C++/CX предоставляет конкретные реализации C++ в файле заголовка collection.h. На этой иллюстрации показаны связи между типами коллекций:

Схема дерева наследования C плюс C плюс C X для типов коллекций.

Vector usage

Когда класс должен передать контейнер последовательности другому компоненту среды выполнения Windows, используйте Windows::Foundation::Collections::IVector<T> его в качестве параметра или возвращаемого типа, а Platform::Collections::Vector<T> также в качестве конкретной реализации. При попытке использования типа Vector в качестве открытого возвращаемого значения или параметра возникнет ошибка компилятора C3986. Эту ошибку можно исправить, заменив Vector объектом IVector.

Important

В случае передачи последовательности внутри разрабатываемой программы используйте Vector или std::vector , поскольку они более эффективны по сравнению с IVector. Используйте IVector только при передаче контейнера с помощью ABI.

Система типов среда выполнения Windows не поддерживает концепцию сорных массивов, поэтому нельзя передать IVector<Platform::Array<T>> в качестве возвращаемого значения или параметра метода. Для передачи массива массивов или последовательности массивов в ABI используйте IVector<IVector<T>^>.

КлассVector<T> предоставляет методы, необходимые для добавления и удаления элементов коллекции и доступа к ним. Его можно неявно преобразовать в класс IVector<T>. Алгоритмы STL также можно применять к экземплярам Vector<T>. В следующем примере демонстрируются некоторые простейшие варианты использования. Функция begin иend функция здесь находятся из 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::Foundation::DateTime, или для пользовательских сравнений, например objA->UniqueID == objB->UniqueID, необходимо предоставить пользовательский объект функции.

VectorProxy elements

Platform::Collections::VectorIterator и Platform::Collections::VectorViewIterator позволяют использовать циклы и алгоритмы, такие как range for с контейнером 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 и VectorProxy упоминается в тексте предупреждения.

На следующем рисунке показан цикл range for с контейнерами IVector<Person^>. Обратите внимание, что выполнение прекращается в точке останова на строке 64. В окне QuickWatch показывается, что переменная итератора p на самом деле является VectorProxy<Person^>, у которого есть переменные-члены m_v и m_i. Однако при вызове GetType для этой переменной она возвращает идентичный тип в экземпляр Personp2. Вывод заключается в том, что хотя VectorProxy и ArrowProxy может отображаться в QuickWatch, отладчик некоторых ошибок компилятора или других местах, вам обычно не нужно явно кодировать для них.

Снимок экрана: отладка VectorProxy в цикле for, использующем диапазон.

Один из сценариев, в котором необходимо создать код для прокси-объекта, заключается в следующем: необходимо выполнить операцию 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 usage

В этом примере показано, как вставлять элементы и искать их в объекте 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, должен поддерживать сравнение на меньше со строгим слабым упорядочением, либо неявно, либо с помощью предоставленного настраиваемого std::less компаратора. Скалярные типы поддерживают сравнение неявно. Для нескалярных типов значений, таких как Windows::Foundation::DateTime, или для пользовательских вариантов сравнения (например, objA->UniqueID < objB->UniqueID) необходимо определять специальный алгоритм сравнения.

Collection types

Коллекции подразделяются на четыре категории: изменяемые и доступные только для чтения версии последовательных и ассоциативных коллекций. Кроме того, C++/CX улучшает коллекции, предоставляя три класса итератора, упрощающие доступ к коллекциям.

Элементы модифицируемой коллекции могут быть изменены, но элементы коллекции только для чтения, которая называется представлением, можно только прочитать. Элементы Platform::Collections::Vector или Platform::Collections::VectorView коллекции можно обработать с помощью итератора и индекса коллекции Vector::GetAt. К элементам ассоциативной коллекции можно обращаться, используя коллекцию Map::Lookup и ключ.

Platform::Collections::Map Класс
Изменяемая ассоциативная коллекция. Элементы объекта Map представляют собой пары "ключ-значение". Поддерживается как поиск значения по связанному с ним ключу, так и перебор всех пар "ключ-значение".

В классахMap и MapView используется шаблон <K, V, C = std::less<K>>; таким образом, алгоритм сравнения можно изменять. Кроме того, в классах Vector и VectorView используется шаблон <T, E = std::equal_to<T>> , поэтому поведение метода IndexOf()можно изменять. Это важно в основном для объектов Vector и VectorView , содержащих структуры значения. Например, чтобы создать Vector<Windows::Foundation::DateTime> объект, необходимо предоставить пользовательский компаратор, так как DateTime не перегружает == оператор.

Platform::Collections::MapView Класс
Версия объекта Mapтолько для чтения.

Platform::Collections::Vector Класс
Изменяемая коллекция последовательностей. Vector<T> поддерживает случайный доступ с постоянной временной сложностью и операции с амортизированной временной сложностью Append.

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 и end, которые являются немемберными.

В следующей таблице перечислены все доступные итераторы и функции.

Iterators Functions
Platform::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>^)
Platform::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::Collections::Details::MapChangedEventArgs и Platform::Collections::Details::VectorChangedEventArgs ref классы хранят аргументы событий, чтобы определить, что вызвало событие. *EventArgs Типы определяются в Details пространстве имен, так как вам не нужно создавать или использовать их явным образом при использовании Map илиVector.

See also

Type System
Справочник по языку C++/CX
Namespaces Reference