Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
In a C++/CX program, you can make free use of Standard Template Library (STL) containers, or any other user-defined collection type. However, when you pass collections back and forth across the Windows Runtime application binary interface (ABI)—for example, to a XAML control or to a JavaScript client—you must use Windows Runtime collection types.
The Windows Runtime defines the interfaces for collections and related types, and C++/CX provides the concrete C++ implementations in the collection.h header file. This illustration shows the relationships between the collection types:
The
Platform::Collections::Vector
class resembles thestd::vector
class.The
Platform::Collections::Map
class resembles thestd::map
class.Platform::Collections::VectorView
class andPlatform::Collections::MapView
class are read-only versions ofVector
andMap
.Iterators are defined in the
Platform::Collections
Namespace. These iterators satisfy the requirements for STL iterators and enable the use ofstd::find
,std::count_if
, and other STL algorithms on anyWindows::Foundation::Collections
interface type orPlatform::Collections
concrete type. For example, this means that you can iterate a collection in a Windows Runtime component that's created in C# and apply an STL algorithm to it.Important
Proxy iterators
VectorIterator
andVectorViewIterator
utilize proxy objectsVectorProxy<T>
andArrowProxy<T>
to enable usage with STL containers. For more information, see VectorProxy elements later in this article.The C++/CX collection types support the same thread safety guarantees that STL containers support.
Windows::Foundation::Collections::IObservableVector
andWindows::Foundation::Collections::IObservableMap
define events that are fired when the collection changes in various ways. By implementing these interfaces,Platform::Collections::Map
andPlatform::Collections::Vector
support databinding with XAML collections. For example, if you have aVector
that is data-bound to aGrid
, when you add an item to a collection, the change is reflected in the Grid UI.
Vector usage
When your class has to pass a sequence container to another Windows Runtime component, use Windows::Foundation::Collections::IVector<T>
as the parameter or return type, and Platform::Collections::Vector<T>
as the concrete implementation. If you attempt to use a Vector
type in a public return value or parameter, compiler error C3986 will be raised. You can fix the error by changing the Vector
to an IVector
.
Important
If you are passing a sequence within your own program, then use either Vector
or std::vector
because they are more efficient than IVector
. Use IVector
only when you pass the container across the ABI.
The Windows Runtime type system does not support the concept of jagged arrays and therefore you cannot pass an IVector<Platform::Array<T>>
as a return value or method parameter. To pass a jagged array or a sequence of sequences across the ABI, use IVector<IVector<T>^>
.
Vector<T>
provides the methods that are required for adding, removing, and accessing items in the collection, and it is implicitly convertible to IVector<T>
. You can also use STL algorithms on instances of Vector<T>
. The following example demonstrates some basic usage. The begin
function and end
function here are from the Platform::Collections
namespace, not the 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();
}
If you have existing code that uses std::vector
and you want to reuse it in a Windows Runtime component, just use one of the Vector
constructors that takes a std::vector
or a pair of iterators to construct a Vector
at the point where you pass the collection across the ABI. The following example shows how to use the Vector
move constructor for efficient initialization from a std::vector
. After the move operation, the original vec
variable is no longer valid.
//#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));
}
If you have a vector of strings that you must pass across the ABI at some future point, you must decide whether to create the strings initially as std::wstring
types or as Platform::String^
types. If you have to do a lot of processing on the strings, then use wstring
. Otherwise, create the strings as Platform::String^
types and avoid the cost of converting them later. You must also decide whether to put these strings into a std::vector
or Platform::Collections::Vector
internally. As a general practice, use std::vector
and then create a Platform::Vector
from it only when you pass the container across the ABI.
Value types in Vector
Any element to be stored in a Platform::Collections::Vector
must support equality comparison, either implicitly or by using a custom std::equal_to
comparator that you provide. All reference types and all scalar types implicitly support equality comparisons. For non-scalar value types such as Windows::Foundation::DateTime
, or for custom comparisons—for example, objA->UniqueID == objB->UniqueID
—you must provide a custom function object.
VectorProxy elements
Platform::Collections::VectorIterator
and Platform::Collections::VectorViewIterator
enable the use of range for
loops and algorithms like std::sort
with an IVector<T>
container. But IVector
elements cannot be accessed through C++ pointer dereference; they can be accessed only through GetAt
and SetAt
methods. Therefore, these iterators use the proxy classes Platform::Details::VectorProxy<T>
and Platform::Details::ArrowProxy<T>
to provide access to the individual elements through *
, ->
, and []
operators, as required by the Standard Library. Strictly speaking, given an IVector<Person^> vec
, the type of *begin(vec)
is VectorProxy<Person^>
. However, the proxy object is almost always transparent to your code. These proxy objects are not documented because they are only for internal use by the iterators, but it is useful to know how the mechanism works.
When you use a range-based for
loop over IVector
containers, use auto&&
to enable the iterator variable to bind correctly to the VectorProxy
elements. If you use auto&
, compiler warning C4239 is raised and VectorProxy
is mentioned in the warning text.
The following illustration shows a range for
loop over an IVector<Person^>
. Notice that execution is stopped on the breakpoint on line 64. The QuickWatch window shows that the iterator variable p
is in fact a VectorProxy<Person^>
that has m_v
and m_i
member variables. However, when you call GetType
on this variable, it returns the identical type to the Person
instance p2
. The takeaway is that although VectorProxy
and ArrowProxy
might appear in QuickWatch, the debugger certain compiler errors, or other places, you typically don't have to explicitly code for them.
One scenario in which you have to code around the proxy object is when you have to perform a dynamic_cast
on the elements—for example, when you are looking for XAML objects of a particular type in a UIElement
element collection. In this case, you must first cast the element to Platform::Object
^ and then perform the dynamic cast:
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
This example shows how to insert items and look them up in a Platform::Collections::Map
, and then return the Map
as a read-only Windows::Foundation::Collections::IMapView
type.
//#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();
}
In general, for internal map functionality, prefer the std::map
type for performance reasons. If you have to pass the container across the ABI, construct a Platform::Collections::Map
from the std::map
and return the Map
as an Windows::Foundation::Collections::IMap
. If you attempt to use a Map
type in a public return value or parameter, compiler error C3986 will be raised. You can fix the error by changing the Map
to an IMap
. In some cases—for example, if you are not making a large number of lookups or insertions, and you are passing the collection across the ABI frequently—it might be less expensive to use Platform::Collections::Map
from the beginning and avoid the cost of converting the std::map
. In any case, avoid lookup and insert operations on an IMap
because these are the least performant of the three types. Convert to IMap
only at the point that you pass the container across the ABI.
Value types in Map
Elements in a Platform::Collections::Map
are ordered. Any element to be stored in a Map
must support less-than comparison with strict weak ordering, either implicitly or by using a custom std::less
comparator that you provide. Scalar types support the comparison implicitly. For non-scalar value types such as Windows::Foundation::DateTime
, or for custom comparisons—for example, objA->UniqueID < objB->UniqueID
—you must provide a custom comparator.
Collection types
Collections fall into four categories: modifiable versions and read-only versions of sequence collections and associative collections. In addition, C++/CX enhances collections by providing three iterator classes that simplify the accessing of collections.
Elements of a modifiable collection can be changed, but elements of a read-only collection, which is known as a view, can only be read. Elements of a Platform::Collections::Vector
or Platform::Collections::VectorView
collection can be accessed by using an iterator or the collection's Vector::GetAt
and an index. Elements of an associative collection can be accessed by using the collection's Map::Lookup
and a key.
Platform::Collections::Map
class
A modifiable, associative collection. Map elements are key-value pairs. Looking up a key to retrieve its associated value, and iterating through all key-value pairs, are both supported.
Map
and MapView
are templated on <K, V, C = std::less<K>>
; therefore, you can customize the comparator. Additionally, Vector
and VectorView
are templated on <T, E = std::equal_to<T>>
so that you can customize the behavior of IndexOf()
. This is important mostly for Vector
and VectorView
of value structs. For example, to create a Vector<Windows::Foundation::DateTime>
, you must provide a custom comparator because DateTime does not overload the ==
operator.
Platform::Collections::MapView
class
A read-only version of a Map
.
Platform::Collections::Vector
class
A modifiable sequence collection. Vector<T>
supports constant-time random access and amortized-constant-time Append
operations.
Platform::Collections::VectorView
class
A read-only version of a Vector
.
Platform::Collections::InputIterator
class
An STL iterator that satisfies the requirements of an STL input iterator.
Platform::Collections::VectorIterator
class
An STL iterator that satisfies the requirements of an STL mutable random-access iterator.
Platform::Collections::VectorViewIterator
class
An STL iterator that satisfies the requirements of an STL const
random-access iterator.
begin() and end() functions
To simplify the use of the STL to process Vector
, VectorView
, Map
, MapView
, and arbitrary Windows::Foundation::Collections
objects, C++/CX supports overloads of the begin
Function and end
Function non-member functions.
The following table lists the available iterators and functions.
Iterators | Functions |
---|---|
Platform::Collections::VectorIterator<T> (Internally stores Windows::Foundation::Collections::IVector<T> and int .) |
begin / end (Windows::Foundation::Collections::IVector<T> ) |
Platform::Collections::VectorViewIterator<T> (Internally stores IVectorView<T> ^ and int .) |
begin / end (IVectorView<T> ^) |
Platform::Collections::InputIterator<T> (Internally stores IIterator<T> ^ and T .) |
begin / end (IIterable<T> ) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Internally stores IIterator<T> ^ and T .) |
begin / end (IMap<K,V> ) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Internally stores IIterator<T> ^ and T .) |
begin / end (Windows::Foundation::Collections::IMapView ) |
Collection change events
Vector
and Map
support databinding in XAML collections by implementing events that occur when a collection object is changed or reset, or when any element of a collection is inserted, removed, or changed. You can write your own types that support databinding, although you cannot inherit from Map
or Vector
because those types are sealed.
The Windows::Foundation::Collections::VectorChangedEventHandler
and Windows::Foundation::Collections::MapChangedEventHandler
delegates specify the signatures for event handlers for collection change events. The Windows::Foundation::Collections::CollectionChange
public enum class, and Platform::Collections::Details::MapChangedEventArgs
and Platform::Collections::Details::VectorChangedEventArgs
ref classes, store the event arguments to determine what caused the event. The *EventArgs
types are defined in the Details
namespace because you don't have to construct or consume them explicitly when you use Map
or Vector
.