Array と WriteOnlyArray (C++/CX)
C++/CX プログラムでは、正規の C スタイル配列または std::array
を自由に使用できます (ただし、std::vector
の方が適していることが多い) が、メタデータで発行されるどの API においても、使用法に応じて、C スタイル配列またはベクターを Platform::Array
型または Platform::WriteOnlyArray
型に変換する必要があります。 Platform::Array
型は、std::vector
ほどには効率的でも強力でもありません。そのため、一般的なガイドラインとして、配列要素で多くの操作を実行する内部コードでは使用を避ける必要があります。
次の配列型は、ABI を介して渡すことができます。
const Platform::Array^
Platform::Array^*
Platform::WriteOnlyArray
Platform::Array^
の戻り値
これらの配列型は、Windows ランタイムによって定義された 3 種類の配列パターンの実装に使用します。
PassArray
呼び出し元が、配列をメソッドに渡すときに使用します。 C++ 入力パラメーターの型は、const
Platform::Array
<T> です。
FillArray
呼び出し元が、メソッドが入力する配列を渡すときに使用します。 C++ 入力パラメーターの型は、Platform::WriteOnlyArray
<T> です。
ReceiveArray
呼び出し元が、メソッドが割り当てる配列を受け取るときに使用します。 C++/CX では、配列を Array^ として戻り値で返すことも、型 Array^* として Out パラメーターとして返すこともできます。
PassArray パターン
クライアント コードが配列を C++ メソッドに渡し、メソッドがその配列を変更しない場合、メソッドはその配列を const Array^
として受け入れます。 Windows ランタイム アプリケーション バイナリ インターフェイス (ABI) レベルでは、これは PassArray と呼ばれます。 次の例は、JavaScript に割り当てられた配列を、読み取り側の C++ 関数に渡す方法を示しています。
//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;
}
次のスニペットは、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;
}
ReceiveArray パターン
ReceiveArray パターンでは、クライアント コードは配列を宣言し、それにメモリを割り当てて初期化するメソッドに渡します。 C++ 入力パラメーターの型は、ハットへのポインター (Array<T>^*
) です。 次の例は、JavaScript で配列オブジェクトを宣言し、それを、メモリを割り当て、要素を初期化して JavaScript に返す C++ 関数に渡す方法を示しています。 JavaScript は、割り当てられた配列を戻り値として扱いますが、C++ 関数は出力パラメーターとして扱います。
//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] + " ";
}
}
次のスニペットは、C++ メソッドを実装する 2 通りの方法を示します。
// 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;
}
Fill 配列
配列を呼び出し元で割り当て、呼び出し先で初期化または変更する場合は、 WriteOnlyArray
を使用します。 次の例は、 WriteOnlyArray
を使用する C++ 関数を実装して、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] + " ";
}
}
次のスニペットは、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;
}
}
配列変換
この例では、Platform::Array
を使用して、その他の種類のコレクションを構築する方法を示しています。
#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);
}
}
次の例は、Platform::Array
を C スタイル配列から構築して、パブリック メソッドから返す方法を示しています。
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);
}
ジャグ配列
Windows ランタイムの型システムは、ジャグ配列の概念をサポートしていないため、パブリック メソッドで IVector<Platform::Array<T>>
を戻り値またはメソッド パラメーターとして使用することはできません。 ABI を通じてジャグ配列またはシーケンスのシーケンスを渡すには、 IVector<IVector<T>^>
を使用します。
ArrayReference 使用による、データ コピーの回避
データが ABI を介して Platform::Array
に渡されており、最終的にはそのデータを C スタイル配列で処理して効率性を追求するシナリオでは、Platform::ArrayReference を使用して、不要なコピー操作を回避できます。 Platform::Array
を受け取るパラメーターに引数として Platform::ArrayReference
が渡されると、ArrayReference
は、そのデータを指定された C スタイル配列に直接格納します。 ArrayReference
にソース データへのロック オンがないため、呼び出しが完了する前に別のスレッドでそのデータが変更されるかまたは削除された場合、結果は不確定になることに注意してください。
次のコード スニペットは、DataReader
操作の結果を Platform::Array
にコピーする方法 (通常のパターン) と、ArrayReference
を代わりに使用してデータを 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) );
}
};
配列をプロパティとして公開することを回避する方法
一般に、ref クラスで Platform::Array
型をプロパティとして公開することは避ける必要があります。これは、クライアント コードが単一要素にアクセスしようとしている場合でも、配列全体が返されるためです。 パブリック ref クラスでシーケンス コンテナーをプロパティとして公開する必要があるときは、Windows::Foundation::IVector
の方が適切です。 プライベートまたは内部 API (メタデータに発行されません) では、std::vector
などの標準 C++ コンテナーの使用を検討してください。