Array et WriteOnlyArray (C++/CX)

Vous pouvez librement utiliser des tableaux de style C ou std::array dans un programme C++/CX (bien que ce soit std::vector souvent un meilleur choix), mais dans toute API publiée dans les métadonnées, vous devez convertir un tableau ou un vecteur de style C en un type Platform::Array ou Platform::WriteOnlyArray un autre, en fonction de la manière dont il est utilisé. Le type Platform::Array n’est pas aussi efficace ni aussi puissant que le type std::vector, donc en règle générale, vous devez éviter de l’utiliser dans le code interne qui exécute un grand nombre d’opérations sur les éléments de tableau.

Les types de tableau suivants peuvent être passés à travers l'ABI :

  1. const Platform::Array^

  2. Platform::Array^*

  3. Platform::WriteOnlyArray

  4. valeur de retour de Platform::Array^

Utilisez ces types de tableau pour implémenter les trois types de modèles de tableau définis par Windows Runtime.

PassArray
Utilisé lorsque l'appelant passe un tableau à une méthode. Le type de paramètre d’entrée C++ est const Platform::Array<T>.

FillArray
Utilisé lorsque l'appelant passe un tableau à remplir par la méthode. Le type de paramètre d’entrée C++ est Platform::WriteOnlyArray<T>.

ReceiveArray
Utilisé lorsque l'appelant reçoit un tableau que la méthode alloue. En langage C++/CX, vous pouvez retourner un tableau en valeur de retour comme un Array^, ou vous pouvez le retourner comme paramètre de sortie de type Array^*.

Modèle PassArray

Lorsque le code client passe un tableau à une méthode C++ et que la méthode ne le modifie pas, la méthode accepte le tableau comme un const Array^. Au niveau de l’interface binaire d’application (ABI) Windows Runtime (ABI), cela s’appelle un PassArray. L'exemple ci-dessous montre comment passer un tableau alloué en JavaScript à la fonction C++ qui le lit.

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

L'extrait de code suivant illustre la méthode 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;
}

Modèle ReceiveArray

Dans le modèle ReceiveArray, le code client déclare un tableau et le passe à une méthode qui lui alloue de la mémoire et l’initialise. Le type de paramètre d’entrée C++ est un pointeur chapeau : Array<T>^*. L'exemple suivant indique comment déclarer un objet tableau dans JavaScript et le passer à une fonction C++ qui alloue de la mémoire, initialise les éléments et le retourne à JavaScript. JavaScript traite le tableau alloué comme une valeur de retour, mais la fonction C++ le traite comme un paramètre de sortie.

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

L'extrait de code suivant montre deux façons d'implémenter la méthode 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;
}

Remplir les tableaux

Lorsque vous souhaitez allouer un tableau dans l'appelant et l'initialiser ou le modifier dans l'appelé, utilisez WriteOnlyArray. L'exemple ci-dessous indique comment implémenter une fonction c++ qui utilise WriteOnlyArray et l'appelle à partir de 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] + " ";
    }
}

L'extrait de code suivant montre comment implémenter la méthode 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;
    }   
}

Conversions de tableau

L’exemple ci-dessous montre comment utiliser un objet Platform::Array pour construire d’autres types de collections :

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

L’exemple ci-dessous montre comment construire un objet Platform::Array à partir d’un tableau de style C et le retourner à partir d’une méthode publique.

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

Tableaux en escalier

Le système de types Windows Runtime ne prend pas en charge le concept des tableaux en escalier et vous ne pouvez pas donc pas utiliser IVector<Platform::Array<T>> comme valeur de retour ou paramètre de méthode dans une méthode publique. Pour passer un tableau en escalier ou une séquence de séquences à travers l'ABI, utilisez IVector<IVector<T>^>.

Utilisez le type ArrayReference pour éviter de copier les données.

Dans certains scénarios où les données sont passées à travers l’ABI dans un Platform::Array et où vous voulez finalement traiter ces données dans un tableau de style C pour plus d’efficacité, vous pouvez utiliser Platform::ArrayReference pour éviter l’opération de copie supplémentaire. Lorsque vous passez un type Platform::ArrayReference comme argument à un paramètre qui accepte un Platform::Array, le ArrayReference stocke les données directement dans un tableau de style C que vous spécifiez. Gardez à l'esprit que le type ArrayReference ne peut effectuer aucun verrouillage sur les données sources. Ainsi, si ces données sont modifiées ou supprimées sur un autre thread avant l'appel, les résultats seront non définis.

L’extrait de code suivant montre comment copier les résultats d’une opération DataReader dans un Platform::Array (le modèle habituel), puis comment substituer ArrayReference pour copier les données directement dans un tableau de style 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) );
    }
};

Évitez d'exposer un tableau comme propriété

En général, vous devez éviter d'exposer un type Platform::Array en tant que propriété dans une classe ref, car le tableau entier est retourné même si le code client tente uniquement d'accéder à un seul élément. Quand vous devez exposer un conteneur de séquence en tant que propriété dans une classe ref publique, choisissez plutôt Windows::Foundation::IVector. Dans les API privées ou internes (qui ne sont pas publiées en métadonnées), envisagez d’utiliser un conteneur C++ standard tel que le type std::vector.

Voir aussi

Système de type
Informations de référence sur le langage C++/CX
Référence aux espaces de noms