Array und WriteOnlyArray (C++/CX)

Sie können normale C-Formatarrays oder std::array in einem C++/CX-Programm (obwohl std::vector häufig eine bessere Wahl ist), aber in jeder API, die in Metadaten veröffentlicht wird, müssen Sie ein C-Formatarray oder einen Vektor in einen oder Platform::WriteOnlyArray typ Platform::Array konvertieren, je nachdem, wie es verwendet wird. Der Platform::Array Typ ist weder so effizient noch so leistungsfähig wie std::vector, daher sollten Sie die Verwendung in internem Code vermeiden, der viele Vorgänge für die Arrayelemente 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^

Sie verwenden diese Arraytypen, um die drei Arten von Arraymustern zu implementieren, die durch die Windows-Runtime definiert werden.

PassArray
Wird verwendet, wenn vom Aufrufer ein Array an eine Methode übergeben wird. Der C++-Eingabeparametertyp ist constPlatform::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 Clientcode ein Array an eine C++-Methode übergibt und die Methode es nicht ändert, akzeptiert die Methode das Array als ein const Array^. Auf der Ebene Windows-Runtime Application Binary Interface (ABI) 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 deklariert der Clientcode ein Array und übergibt es an eine Methode, die den Speicher dafür zuweist und initialisiert. Der Typ des C++-Eingabeparameters ist ein Zeiger-zu-Hut: 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 Sie andere Platform::Array Arten von Auflistungen 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);
    }   
}

Das nächste Beispiel zeigt, wie Sie ein Platform::Array Array im C-Stil erstellen und aus einer öffentlichen Methode zurückgeben.

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 in eine Platform::ArrayABI übergeben werden, und Sie letztendlich diese Daten in einem C-Formatarray aus Effizienzgründen verarbeiten möchten, können Sie Platform::ArrayReference verwenden, um den zusätzlichen Kopiervorgang zu vermeiden. Wenn Sie ein Platform::ArrayReference Argument als Argument an einen Parameter übergeben, der ein Platform::ArrayParameter verwendet, speichert die ArrayReference Daten direkt in einem von Ihnen angegebenen C-Formatarray. 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 Codeausschnitt zeigt, wie die Ergebnisse eines DataReader Vorgangs in ein Platform::Array (das übliche Muster) kopiert werden, und wie Sie die Daten dann direkt ArrayReference in ein C-Formatarray 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 Referenzklasse verfügbar machen müssen, Windows::Foundation::IVector ist dies eine bessere Wahl. In privaten oder internen APIs (die nicht in Metadaten veröffentlicht werden), sollten Sie einen C++-Standardcontainer wie z std::vector. B. verwenden.

Siehe auch

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