Matris och WriteOnlyArray (C++/CX)

Du kan fritt använda vanliga C-formatmatriser eller std::array i ett C++/CX-program (även om std::vector det ofta är ett bättre val), men i alla API:er som publiceras i metadata måste du konvertera en C-formatmatris eller vektor till en Platform::Array eller Platform::WriteOnlyArray typ beroende på hur den används. Typen Platform::Array är varken lika effektiv eller så kraftfull som std::vector, så som en allmän riktlinje bör du undvika att den används i intern kod som utför många åtgärder på matriselementen.

Följande matristyper kan skickas via ABI:

  1. const Platform::Array^

  2. Platform::Array^*

  3. Platform::WriteOnlyArray

  4. returvärde för Platform::Array^

Du använder dessa matristyper för att implementera de tre typer av matrismönster som definieras av Windows Runtime.

PassArray
Används när anroparen skickar en matris till en metod. Parametertypen C++-indata är constPlatform::Array<T.>

FillArray
Används när anroparen skickar en matris som metoden ska fyllas i. Parametertypen C++-indata är Platform::WriteOnlyArray<T>.

ReceiveArray
Används när anroparen tar emot en matris som metoden allokerar. I C++/CX kan du returnera matrisen i returvärdet som en matris^ eller returnera den som en out-parameter som typ Array^*.

PassArray-mönster

När klientkoden skickar en matris till en C++-metod och metoden inte ändrar den, accepterar metoden matrisen som en const Array^. På ABI-nivån (Windows Runtime Application Binary Interface) kallas detta för PassArray. I nästa exempel visas hur du skickar en matris som allokeras i JavaScript till en C++-funktion som läser från den.

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

Följande kodfragment visar C++-metoden:

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-mönster

I mönstret ReceiveArray deklarerar klientkoden en matris och skickar den till en metod som allokerar minnet för den och initierar den. Parametertypen C++-indata är en pekare-till-hatt: Array<T>^*. I följande exempel visas hur du deklarerar ett matrisobjekt i JavaScript och skickar det till en C++-funktion som allokerar minnet, initierar elementen och returnerar det till JavaScript. JavaScript behandlar den allokerade matrisen som ett returvärde, men funktionen C++ behandlar den som en 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] + " ";
    }
}

Följande kodfragment visar två sätt att implementera C++-metoden:


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

Fyllningsmatriser

När du vill allokera en matris i anroparen och initiera eller ändra den i anroparen använder du WriteOnlyArray. I nästa exempel visas hur du implementerar en C++-funktion som använder WriteOnlyArray och anropar den från 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] + " ";
    }
}

Följande kodfragment visar hur du implementerar C++-metoden:

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

Matriskonverteringar

Det här exemplet visar hur du använder en Platform::Array för att konstruera andra typer av samlingar:

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

I nästa exempel visas hur du konstruerar en Platform::Array från en C-matris och returnerar den från en offentlig metod.

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

Ojämna matriser

Windows Runtime-typsystemet stöder inte begreppet ojämna matriser och därför kan du inte använda IVector<Platform::Array<T>> som ett returvärde eller en metodparameter i en offentlig metod. Om du vill skicka en ojämn matris eller en sekvens med sekvenser över ABI använder du IVector<IVector<T>^>.

Använd ArrayReference för att undvika att kopiera data

I vissa scenarier där data skickas över ABI till en Platform::Array, och du slutligen vill bearbeta dessa data i en C-matris för effektivitet, kan du använda Platform::ArrayReference för att undvika den extra kopieringsåtgärden. När du skickar ett Platform::ArrayReference som ett argument till en parameter som tar en Platform::Array, ArrayReference kommer data att lagras direkt i en C-formatmatris som du anger. Tänk bara på att ArrayReference det inte finns något lås på källdata, så om data ändras eller tas bort i en annan tråd innan anropet slutförs kommer resultatet att vara odefinierat.

Följande kodfragment visar hur du kopierar resultatet av en DataReader åtgärd till ett Platform::Array (det vanliga mönstret) och sedan hur du ersätter ArrayReference för att kopiera data direkt till en C-matris:

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

Undvik att exponera en matris som en egenskap

I allmänhet bör du undvika att exponera en Platform::Array typ som en egenskap i en referensklass eftersom hela matrisen returneras även när klientkoden bara försöker komma åt ett enda element. När du behöver exponera en sekvenscontainer som en egenskap i en offentlig referensklass är Windows::Foundation::IVector ett bättre val. I privata eller interna API:er (som inte har publicerats till metadata) bör du överväga att använda en C++-standardcontainer som std::vector.

Se även

typsystem
C++/CX-språkreferens
referens för namnområden