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 런타임에서 정의되는 세 가지 종류의 배열 패턴을 구현합니다.
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++ 메서드를 구현하는 두 가지 방법을 보여 줍니다.
// 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 스타일 배열에서 Platform::Array
를 생성하고 public 메서드에서 반환하는 방법을 보여줍니다.
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 런타임 형식 시스템에서는 가변 배열의 개념이 지원되지 않으므로 public 메서드에서 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
형식을 속성으로 노출하지 않아야 합니다. 클라이언트 코드가 단일 요소에만 액세스하려고 하는 경우에도 전체 배열이 반환되기 때문입니다. public ref 클래스에서 시퀀스 컨테이너를 속성으로 노출해야 하는 경우 Windows::Foundation::IVector
를 선택하는 것이 더 낫습니다. 메타데이터에 게시되지 않는 전용 또는 내부 API에서는 std::vector
와 같은 표준 C++ 컨테이너를 사용하는 것이 좋습니다.