Array 和 WriteOnlyArray (C++/CX)
您可以在 C++/CX 程式中任意使用標準 C-Style 陣列或 std::array
(雖然 std::vector
通常是比較好的選擇),但若是在中繼資料中所發行的任何 API 中,您必須根據 C-Style 陣列或向量的用途,將其轉換為 Platform::Array
或 Platform::WriteOnlyArray
類型。 Platform::Array
類型的效率及功能都不如 std::vector
,因此一般來說,您應該避免在對陣列元素執行許多作業的內部程式碼中使用此類型。
下列陣列類型可以透過 ABI 傳遞:
const Platform::Array^
Platform::Array^*
Platform::WriteOnlyArray
傳回
Platform::Array^
的值
您可以使用這些陣列類型,實作 Windows 執行階段所定義的三種陣列模式類型。
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++ 輸入參數類型為 Hat 指標:Array<T>^*
。 下列範例顯示如何在 JavaScript 中宣告陣列物件,並將它傳遞至 C++ 函式,此函式會配置記憶體、初始化元素,然後將它傳回至 JavaScript。 JavaScript 將配置的陣列視為傳回值,但 C++ 函式將它視為 out 參數。
//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++ 方法的兩種方式:
// 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;
}
填入陣列
當您想要在呼叫端配置陣列,並在被呼叫端初始化或修改它時,請使用 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);
}
}
下一個範例顯示如何從 C-Style 陣列建構 Platform::Array
,並從公用方法中傳回它。
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-Style 陣列中處理資料以提升效率的某些情況下,您可以使用 Platform::ArrayReference 避免額外的複製作業。 當您將 Platform::ArrayReference
當做引數傳遞給採用 Platform::Array
的參數時,ArrayReference
會將資料直接儲存到您指定的 C-Style 陣列中。 請注意, ArrayReference
不會鎖定來源資料,因此如果在呼叫完成之前修改或刪除另一個執行緒上的資料,結果會是未定義的。
下列程式碼片段示範如何將 DataReader
作業的結果複製到 Platform::Array
中 (一般模式),以及如何接著替代 ArrayReference
,將資料直接複製到 C-Style 陣列中:
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) );
}
};
避免將陣列公開為屬性
一般而言,您應該避免將 Platform::Array
類型公開為 ref 類別中的屬性,因為即使用戶端程式碼只嘗試存取單一元素,也會傳回整個陣列。 當您必須將序列容器公開為公用 ref 類別中的屬性時,Windows::Foundation::IVector
會是較佳選擇。 在私用或內部應用程式開發介面中 (不會發行到中繼資料),請考慮使用 Standard C++ 容器,例如 std::vector
。