Array und WriteOnlyArray (C++/CX)

Sie können normale Arrays im C-Format oder std::array in einem C++-/CX-Programm verwenden (auch wenn std::vector häufig eine bessere Wahl ist), aber in jeder API, die in den Metadaten veröffentlicht wird, müssen Sie ein Array oder einen Vektor im C-Format je nach Anwendungsfall in den Typ Platform::Array oder Platform::WriteOnlyArray konvertieren. Der Typ Platform::Array ist weder so effizient noch so leistungsfähig wie std::vector. Als allgemeine Richtlinie sollten Sie daher dessen Verwendung in internem Code vermeiden, da dieser viele Vorgänge mit den Arrayelementen ausführt.

Die folgenden Arraytypen können über die ABI übergeben werden:

  1. const Platform::Array^

  2. Platform::Array^*

  3. Platform::WriteOnlyArray

  4. Rückgabewert von Platform::Array^

Diese Arraytypen werden verwendet, um die drei Typen von Arraymustern zu implementieren, die von der Windows-Runtime definiert werden.

PassArray
Wird verwendet, wenn vom Aufrufer ein Array an eine Methode übergeben wird. Der C++-Eingabeparametertyp ist const Platform::Array<T>.

FillArray
Wird verwendet, wenn vom Aufrufer ein Array übergeben wird, um die Methode zu füllen. Der C++-Eingabeparametertyp ist Platform::WriteOnlyArray<T>.

ReceiveArray
Wird verwendet, wenn vom Aufrufer ein Array empfangen wird, das von der Methode zugeordnet wird. In C++/CX können Sie das Array im Rückgabewert als Array^ oder in Form eines out-Parameters als Array^*-Typ zurückgeben.

PassArray-Muster

Wenn vom Clientcode ein Array an eine C++-Methode übergeben und von der Methode nicht geändert wird, akzeptiert die Methode das Array als const Array^. Auf der Ebene der Windows-Runtime-ABI (Application Binary Interface) wird dies als PassArray bezeichnet. Im nächsten Beispiel wird gezeigt, wie ein Array übergeben wird, das in JavaScript zu einer C++-Funktion zugeordnet ist, die aus dem Array liest.

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

Im folgenden Codeausschnitt wird die C++-Methode veranschaulicht:

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

ReceiveArray-Muster

Im ReceiveArray-Muster wird ein Array vom Clientcode deklariert und an eine Methode übergeben, die dem Array Speicher zuordnet und es initialisiert. Der C++-Eingabeparametertyp ist ein Zeiger als Caretzeichen: Array<T>^*. Im folgenden Beispiel wird gezeigt, wie ein Arrayobjekt in JavaScript deklariert und an eine C++-Funktion übergeben wird, die Speicher zuordnet, Elemente initialisiert und das Arrayobjekt an JavaScript zurückgibt. Von JavaScript wird das zugeordnete Array als Rückgabewert interpretiert, von der C++-Funktion jedoch als out-Parameter.

//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] + " ";
    }
}

Der folgende Codeausschnitt zeigt zwei Möglichkeiten zur Implementierung der C++-Methode:


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

Füllbereichsarrays

Wenn Sie ein Array im Aufrufer zuordnen und es im Aufgerufenen initialisieren oder ändern möchten, verwenden Sie WriteOnlyArray. Im nächsten Beispiel wird gezeigt, wie eine C++-Funktion, die WriteOnlyArray verwendet, implementiert und aus JavaScript aufgerufen wird.

// 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] + " ";
    }
}

Der folgende Codeausschnitt zeigt, wie die C++-Methode implementiert wird:

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

Arraykonvertierungen

In diesem Beispiel wird gezeigt, wie ein Platform::Array verwendet wird, um andere Typen von Auflistungen zu erstellen:

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

Im nächsten Beispiel wird gezeigt, wie ein Platform::Array aus einem Array im C-Format erstellt und von einer öffentlichen Methode zurückgegeben wird.

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

Verzweigte Arrays

Das Windows Runtime-Typsystem unterstützt nicht das Konzept von verzweigten Arrays. Deshalb können Sie ein IVector<Platform::Array<T>> nicht als Rückgabewert oder Methodenparameter in einer öffentlichen Methode übergeben. Um ein verzweigtes Array oder eine Sequenz von Sequenzen an die ABI zu übergeben, verwenden Sie IVector<IVector<T>^>.

Verwendung von ArrayReference, um das Kopieren von Daten zu vermeiden

In einigen Szenarien, in denen Daten über die ABI an ein Platform::Array übergeben werden und diese Daten aus Effizienzgründen letztlich in einem Array im C-Format verarbeitet werden sollen, können Sie Platform::ArrayReference verwenden, um den zusätzlichen Kopiervorgang zu vermeiden. Wenn Sie Platform::ArrayReference als Argument an einen Parameter übergeben, der ein Platform::Array akzeptiert, speichert ArrayReference die Daten direkt in einem angegebenen Array im C-Format. Beachten Sie, dass ArrayReference nicht über eine Sperre für die Quelldaten verfügt. Wenn diese Daten geändert oder in einem anderen Thread gelöscht werden, bevor der Aufruf abgeschlossen wird, sind die Ergebnisse nicht definiert.

Der folgende Codeschnipsel zeigt, wie die Ergebnisse eines DataReader-Vorgangs in ein Platform::Array (das übliche Muster) kopiert werden und wie ArrayReference ersetzt wird, um die Daten direkt in ein Array im C-Format zu kopieren:

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

Vermeiden, ein Array als Eigenschaft verfügbar zu machen

Im Allgemeinen sollten Sie einen Platform::Array -Typ möglichst nicht als Eigenschaft in einer Verweisklasse verfügbar machen, da das gesamte Array zurückgegeben wird, auch wenn der Clientcode nur versucht, auf ein einzelnes Element zuzugreifen. Wenn Sie einen Sequenzcontainer als Eigenschaft in einer öffentlichen Verweisklasse verfügbar machen müssen, ist Windows::Foundation::IVector die bessere Wahl. In privaten oder internen APIs (die nicht in Metadaten veröffentlicht werden) sollten Sie die Verwendung eines C++-Standardcontainers wie std::vector in Erwägung ziehen.

Weitere Informationen

Typsystem
C++-/CX-Programmiersprachenreferenz
Referenz zu Namespaces