Array e WriteOnlyArray (C++/CX)

È possibile usare liberamente matrici di tipo C o std::array in un programma C++/CX (anche se std::vector spesso è una scelta migliore), ma in qualsiasi API pubblicata nei metadati, è necessario convertire una matrice o un vettore di tipo C in un Platform::Array tipo o Platform::WriteOnlyArray a seconda della modalità di utilizzo. Il Platform::Array tipo non è così efficiente né potente come std::vector, quindi è consigliabile evitare l'uso nel codice interno che esegue molte operazioni sugli elementi della matrice.

I seguenti tipi di matrice possono essere passati attraverso l'ABI:

  1. const Platform::Array^

  2. Platform::Array^*

  3. Platform::WriteOnlyArray

  4. valore restituito di Platform::Array^

Questi tipi di matrice vengono usati per implementare i tre tipi di modelli di matrice definiti da Windows Runtime.

PassArray
Utilizzato quando il chiamante passa una matrice a un metodo. Il tipo di parametro di input C++ è constPlatform::Array<T.>

FillArray
Utilizzato quando il chiamante passa una matrice per il metodo da riempire. Il tipo di parametro di input C++ è Platform::WriteOnlyArray<T>.

ReceiveArray
Utilizzato quando il chiamante riceve una matrice che il metodo alloca. In C++/CX è possibile restituire la matrice nel valore restituito come Array^ oppure come parametro out come tipo Array^*.

Modello PassArray

Quando il codice client passa una matrice a un metodo C++ e il metodo non lo modifica, il metodo accetta la matrice come .const Array^ A livello di ABI (Application Binary Interface) di Windows Runtime, questa operazione è nota come PassArray. Nell'esempio riportato di seguito viene illustrato come passare una matrice allocata in JavaScript a una funzione di C++ che la legge.

//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;
}

Nel frammento riportato di seguito viene mostrato il metodo 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;
}

Modello ReceiveArray

Nel modello ReceiveArray il codice client dichiara una matrice e lo passa a un metodo che alloca la memoria per essa e la inizializza. Il tipo di parametro di input C++ è un puntatore a hat: Array<T>^*. Nell'esempio riportato di seguito viene illustrato come dichiarare un oggetto matrice in JavaScript e passarlo a una funzione di C++ che alloca la memoria, inizializza gli elementi e lo restituisce al linguaggio JavaScript. JavaScript tratta la matrice allocata come un valore restituito, mentre la funzione di C++ la tratta come un parametro 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] + " ";
    }
}

Nel frammento riportato di seguito vengono illustrati due modi per implementare il metodo 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;
}

Matrici di riempimento

Per allocare una matrice nel chiamante e inizializzarla o modificarla nel destinatario della chiamata, utilizza WriteOnlyArray. Nell'esempio riportato di seguito viene illustrato come implementare una funzione di C++ che utilizza l'oggetto WriteOnlyArray e lo chiama da 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] + " ";
    }
}

Nel frammento riportato di seguito viene mostrato come implementare il metodo 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;
    }   
}

Conversioni di matrice

In questo esempio viene illustrato come usare un Platform::Array oggetto per costruire altri tipi di raccolte:

#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);
    }   
}

Nell'esempio seguente viene illustrato come costruire un oggetto Platform::Array da una matrice di tipo C e restituirlo da un metodo pubblico.

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);
}

Matrici di matrici

Il sistema di tipi di Windows Runtime non supporta il concetto di matrici di matrici, pertanto non puoi passare IVector<Platform::Array<T>> come valore restituito o parametro di metodo in un metodo pubblico. Per passare una matrice di matrici o una sequenza di sequenze attraverso l'interfaccia applicativa binaria (ABI), usa IVector<IVector<T>^>.

Utilizza ArrayReference per evitare di copiare i dati

In alcuni scenari in cui i dati vengono passati attraverso l'interfaccia ABI in un Platform::Arrayoggetto e si vuole elaborare i dati in una matrice in stile C per ottenere efficienza, è possibile usare Platform::ArrayReference per evitare l'operazione di copia aggiuntiva. Quando si passa un oggetto Platform::ArrayReference come argomento a un parametro che accetta un Platform::Arrayoggetto , ArrayReference i dati verranno archiviati direttamente in una matrice in stile C specificata. Tieni presente che ArrayReference non ha alcun blocco sui dati di origine. Pertanto, se tali dati vengono modificati o eliminati in un altro thread prima del completamento della chiamata, i risultati saranno non definiti.

Il frammento di codice seguente illustra come copiare i risultati di un'operazione DataReader in un Platform::Array (modello consueto) e quindi come sostituire ArrayReference per copiare i dati direttamente in una matrice in stile 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) );
    }
};

Evitare di esporre una matrice come proprietà

In generale, evita di esporre un tipo Platform::Array come proprietà in una classe di riferimento poiché l'intera matrice viene restituita anche quando il codice client tenta semplicemente di accedere a un singolo elemento. Quando è necessario esporre un contenitore di sequenza come proprietà in una classe di riferimento pubblica, Windows::Foundation::IVector è una scelta migliore. Nelle API private o interne (che non vengono pubblicate nei metadati), prendere in considerazione l'uso di un contenitore C++ standard, ad std::vectoresempio .

Vedi anche

Sistema di tipi
Riferimenti al linguaggio C++/CX
Riferimenti a spazi dei nomi