Array y WriteOnlyArray (C++/CX)

Puedes utilizar libremente matrices normales de estilo C o std::array en un programa de C++/CX (aunque std::vector suele ser preferible), pero en las API publicadas en metadatos, debes convertir una matriz o vector de estilo C a un tipo Platform::Array o Platform::WriteOnlyArray según como se vaya a usar. El tipo Platform::Array no es tan eficaz como std::vector, por lo que, como regla general, no debes utilizarlo en código interno que realice gran cantidad de operaciones en los elementos de la matriz.

Los tipos de matriz siguientes se pueden pasar a través de ABI:

  1. const Platform::Array^

  2. Platform::Array^*

  3. Platform::WriteOnlyArray

  4. valor devuelto de Platform::Array^

Utiliza estos tipos de matriz para implementar los tres tipos de patrones de matriz definidos por Windows Runtime.

PassArray
Se utiliza cuando el llamador pasa una matriz a un método. El tipo de parámetro de entrada de C++ es constPlatform::Array<T>.

FillArray
Se utiliza cuando el llamador pasa una matriz para el método que se va a rellenar. El tipo de parámetro de entrada de C++ es Platform::WriteOnlyArray<T>.

ReceiveArray
Se usa cuando el llamador recibe una matriz que el método asigna. En C++/CX puedes devolver la matriz en el valor devuelto como Array^ o puedes devolverla como parámetro de salida como tipo Array^*.

Patrón PassArray

Cuando el código de cliente pasa una matriz a un método de C++ y el método no la modifica, el método acepta la matriz como const Array^. En el nivel de interfaz binaria de aplicación Windows Runtime, esto se conoce como PassArray. En el ejemplo siguiente se muestra cómo pasar una matriz asignada en JavaScript a una función de C++ que lee en ella.

//JavaScript
function button2_click() {
    var obj = new JS-Array.Class1();
    var a = new Array(100);
    for (i = 0; i < 100; i++) {
        a[i] = i;
    }
    // Notice that method names are camelCased in JavaScript.
    var sum = obj.passArrayForReading(a);
    document.getElementById('results').innerText
        = "The sum of all the numbers is " + sum;
}

En el siguiente fragmento de código se muestra el método de C++:

double Class1::PassArrayForReading(const Array<double>^ arr)
{
    double sum = 0;
    for(unsigned int i = 0 ; i < arr->Length; i++)
    {
        sum += arr[i];
    }
    return sum;
}

Patrón ReceiveArray

En el patrón ReceiveArray, el código de cliente declara una matriz y la pasa a un método que le asigna memoria y la inicializa. El tipo de parámetro de entrada de C++ es un puntero a sombrero: Array<T>^*. En el ejemplo siguiente se muestra cómo se declara un objeto de matriz en JavaScript y cómo se pasa a una función de C++ que asigna memoria, inicializa los elementos y lo devuelve a JavaScript. JavaScript trata la matriz asignada como un valor devuelto, pero la función de C++ la trata como un parámetro out.

//JavaScript
function button3_click() {
    var obj = new JS-Array.Class1();

    // Remember to use camelCase for the function name.
    var array2 = obj.calleeAllocatedDemo2();
    for (j = 0; j < array2.length; j++) {
        document.getElementById('results').innerText += array2[j] + " ";
    }
}

En el fragmento de código siguiente se muestran dos maneras de implementar el método de C++:


// Return array as out parameter...
void Class1::CalleeAllocatedDemo(Array<int>^* arr)
{
    auto temp = ref new Array<int>(10);
    for(unsigned int i = 0; i < temp->Length; i++)
    {
        temp[i] = i;
    }

    *arr = temp;
}

// ...or return array as return value:
Array<int>^ Class1::CalleeAllocatedDemo2()
{
    auto temp = ref new Array<int>(10);    
    for(unsigned int i = 0; i < temp->Length; i++)
    {
        temp[i] = i;
    }

    return temp;
}

Rellenar matrices

Si deseas asignar una matriz en el llamador y la inicializas o modificas en el destinatario, debes usar WriteOnlyArray. En el ejemplo siguiente se muestra cómo se implementa una función de C++ que utiliza WriteOnlyArray y se invoca desde JavaScript.

// JavaScript
function button4_click() {
    var obj = new JS-Array.Class1();
    //Allocate the array.
    var a = new Array(10);

    //Pass the array to C++.
    obj.callerAllocatedDemo(a);

    var results = document.getElementById('results');
    // Display the modified contents.
    for (i = 0; i < 10; i++) {
        document.getElementById('results').innerText += a[i] + " ";
    }
}

En el fragmento de código siguiente se muestra cómo implementar el método de C++:

void Class1::CallerAllocatedDemo(Platform::WriteOnlyArray<int>^ arr)
{
    // You can write to the elements directly.
    for(unsigned int i = 0; i < arr->Length; i++)
    {
        arr[i] = i;
    }   
}

Conversiones de matriz

En este ejemplo se muestra cómo utilizar un Platform::Array para crear otros tipos de colecciones:

#include <vector>
#include <collection.h>
using namespace Platform;
using namespace std;
using namespace Platform::Collections;

void ArrayConversions(const Array<int>^ arr)
{
    // Construct an Array from another Array.
    Platform::Array<int>^ newArr = ref new Platform::Array<int>(arr);

    // Construct a Vector from an Array
    auto v = ref new Platform::Collections::Vector<int>(arr); 

    // Construct a std::vector. Two options.
    vector<int> v1(begin(arr), end(arr));
    vector<int> v2(arr->begin(), arr->end());

    // Initialize a vector one element at a time.
    // using a range for loop. Not as efficient as using begin/end.
    vector<int> v3;
    for(int i : arr)
    {
        v3.push_back(i);
    }   
}

En el ejemplo siguiente se muestra cómo se crea un Platform::Array a partir de una matriz de estilo C y se devuelve desde un método público.

Array<int>^ GetNums()
{
    int nums[] = {0,1,2,3,4};
    //Use nums internally....

    // Convert to Platform::Array and return to caller.
    return ref new Array<int>(nums, 5);
}

Matrices escalonadas

El sistema de tipos de Windows en tiempo de ejecución no admite el concepto de matrices escalonadas y, por consiguiente, no se puede usar IVector<Platform::Array<T>> como valor devuelto o parámetro del método en un método público. Para pasar una matriz escalonada o un grupo de secuencias a través de la ABI, usa IVector<IVector<T>^>.

Usar ArrayReference para evitar la copia de datos

En algunos escenarios donde los datos se pasan a través de la ABI en un Platform::Array y deseas en última instancia que dichos datos se procesen en una matriz de estilo C por razones de eficacia, puedes utilizar Platform::ArrayReference para evitar la operación de copia adicional. Cuando pases un tipo Platform::ArrayReference como argumento a un parámetro que toma un Platform::Array, el ArrayReference almacenará los datos directamente en la matriz de estilo C que especifiques. Solo debes tener en cuenta que ArrayReference no tiene ningún bloqueo en los datos de origen, por lo que si esos datos se modifican o eliminan en otro subproceso antes de completarse la llamada, los resultados serán no definidos (undefined).

En el siguiente fragmento de código se muestra cómo copiar los resultados de una operación DataReader en un Platform::Array (el patrón habitual) y, a continuación, cómo sustituir ArrayReference para copiar los datos directamente en una matriz de estilo C:

public ref class TestReferenceArray sealed
{
public:

    // Assume dr is already initialized with a stream
    void GetArray(Windows::Storage::Streams::DataReader^ dr, int numBytesRemaining)
    {
        // Copy into Platform::Array
        auto bytes = ref new Platform::Array<unsigned char>(numBytesRemaining);            

        // Fill an Array.
        dr->ReadBytes(bytes);

        // Fill a C-style array
        uint8 data[1024];
        dr->ReadBytes( Platform::ArrayReference<uint8>(data, 1024) );
    }
};

Evitar exponer una matriz como una propiedad

En general, debes evitar exponer un tipo Platform::Array como una propiedad de una clase ref porque se devuelve la matriz completa, incluso cuando el código de cliente intenta únicamente acceder a un solo elemento. Cuando necesites exponer un contenedor de secuencias como una propiedad en una clase ref pública, es preferible que uses Windows::Foundation::IVector. En las API privadas o internas (que no se publican para metadatos), considera la opción de utilizar un contenedor de C++ estándar como std::vector.

Consulte también

Sistema de tipos
Referencia del lenguaje C++/CX
Referencia de espacios de nombres